Corrections to SVN properties.
[AROS.git] / workbench / network / smbfs / source_code / main.c
blob19df2c53a2443b1bbc0acacc808ae828d136333f
1 /*
2 * $Id$
4 * :ts=4
6 * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
8 * Copyright (C) 2000-2009 by Olaf `Olsen' Barthel <obarthel -at- gmx -dot- net>
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.
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.
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.
25 #include "smbfs.h"
27 /****************************************************************************/
29 #include "smb_abstraction.h"
31 /****************************************************************************/
33 #include <smb/smb.h>
35 /****************************************************************************/
37 #if defined(__amigaos4__) && !defined(Flush)
38 #define Flush(fh) FFlush(fh)
39 #endif /* __amigaos4__ && !Flush */
41 /****************************************************************************/
43 /* A quick workaround for the timeval/timerequest->TimeVal/TimeRequest
44 change in the recent OS4 header files. */
45 #if defined(__NEW_TIMEVAL_DEFINITION_USED__)
47 #define timeval TimeVal
48 #define tv_secs Seconds
49 #define tv_micro Microseconds
51 #define timerequest TimeRequest
52 #define tr_node Request
53 #define tr_time Time
55 #endif /* __NEW_TIMEVAL_DEFINITION_USED__ */
57 /****************************************************************************/
59 /* This is for backwards compatibility only. */
60 #if defined(__amigaos4__)
61 #define fib_EntryType fib_Obsolete
62 #endif /* __amigaos4__ */
64 /****************************************************************************/
66 #include "smbfs_rev.h"
67 STRPTR Version = VERSTAG;
69 /****************************************************************************/
71 #define UNIX_TIME_OFFSET 252460800
72 #define MAX_FILENAME_LEN 256
74 /****************************************************************************/
76 #define SMB_ROOT_DIR_NAME "\\"
77 #define SMB_PATH_SEPARATOR '\\'
79 /****************************************************************************/
81 typedef STRPTR KEY;
82 typedef LONG * NUMBER;
83 typedef LONG SWITCH;
85 /****************************************************************************/
87 struct FileNode
89 struct MinNode fn_MinNode;
90 struct FileHandle * fn_Handle;
91 LONG fn_Offset;
92 LONG fn_Mode;
93 smba_file_t * fn_File;
94 STRPTR fn_FullName;
97 struct LockNode
99 struct MinNode ln_MinNode;
100 struct FileLock ln_FileLock;
101 smba_file_t * ln_File;
102 BOOL ln_RestartExamine;
103 UWORD ln_Pad;
104 STRPTR ln_FullName;
107 /****************************************************************************/
109 /* The minimum operating system version we require to work. */
110 #define MINIMUM_OS_VERSION 37 /* Kickstart 2.04 or better */
111 /*#define MINIMUM_OS_VERSION 39*/ /* Kickstart 3.0 or better */
113 /****************************************************************************/
115 /* Careful: the memory pool routines in amiga.lib are available only to
116 * SAS/C and similar compilers (not necessarily to GCC).
118 #if defined(__GNUC__) && (MINIMUM_OS_VERSION < 39)
120 #undef MINIMUM_OS_VERSION
121 #define MINIMUM_OS_VERSION 39
123 #endif /* __GNUC__ */
125 /****************************************************************************/
127 #if (MINIMUM_OS_VERSION < 39)
129 /* These are in amiga.lib */
130 APTR ASM AsmCreatePool(REG(d0,ULONG memFlags),REG(d1,ULONG puddleSize),REG(d2,ULONG threshSize),REG(a6,struct Library * SysBase));
131 VOID ASM AsmDeletePool(REG(a0,APTR poolHeader),REG(a6,struct Library * SysBase));
132 APTR ASM AsmAllocPooled(REG(a0,APTR poolHeader),REG(d0,ULONG memSize),REG(a6,struct Library * SysBase));
133 VOID ASM AsmFreePooled(REG(a0,APTR poolHeader),REG(a1,APTR memory),REG(d0,ULONG memSize),REG(a6,struct Library * SysBase));
135 #define CreatePool(memFlags,puddleSize,threshSize) AsmCreatePool((memFlags),(puddleSize),(threshSize),SysBase)
136 #define DeletePool(poolHeader) AsmDeletePool((poolHeader),SysBase)
137 #define AllocPooled(poolHeader,memSize) AsmAllocPooled((poolHeader),(memSize),SysBase)
138 #define FreePooled(poolHeader,memory,memSize) AsmFreePooled((poolHeader),(memory),(memSize),SysBase)
140 #endif /* MINIMUM_OS_VERSION */
142 /****************************************************************************/
144 /* Forward declarations for local routines. */
145 #if !defined(__AROS__)
146 LONG _start(VOID);
147 #endif
148 LONG VARARGS68K LocalPrintf(STRPTR format, ...);
149 STRPTR amitcp_strerror(int error);
150 STRPTR host_strerror(int error);
151 LONG CompareNames(STRPTR a, STRPTR b);
152 VOID StringToUpper(STRPTR s);
153 #ifndef __AROS__
154 VOID VARARGS68K ReportError(STRPTR fmt, ...);
155 #endif
156 VOID FreeMemory(APTR address);
157 APTR AllocateMemory(ULONG size);
158 LONG GetTimeZoneDelta(VOID);
159 ULONG GetCurrentTime(VOID);
160 VOID GMTime(time_t seconds, struct tm *tm);
161 time_t MakeTime(const struct tm *const tm);
162 #ifndef __AROS__
163 VOID VARARGS68K SPrintf(STRPTR buffer, STRPTR formatString, ...);
164 #endif
165 int BroadcastNameQuery(char *name, char *scope, UBYTE *address);
167 /****************************************************************************/
169 INLINE STATIC BOOL ReallyRemoveDosEntry(struct DosList *entry);
170 INLINE STATIC LONG BuildFullName(STRPTR parent_name, STRPTR name, STRPTR *result_ptr, LONG *result_size_ptr);
171 INLINE STATIC VOID TranslateCName(UBYTE *name, UBYTE *map);
172 INLINE STATIC VOID ConvertCString(LONG max_len, APTR bstring, STRPTR cstring);
173 STATIC VOID DisplayErrorList(VOID);
174 STATIC VOID AddError(STRPTR fmt, APTR args);
175 STATIC LONG CVSPrintf(STRPTR format_string, APTR args);
176 STATIC VOID VSPrintf(STRPTR buffer, STRPTR formatString, APTR args);
177 STATIC VOID SendDiskChange(ULONG class);
178 STATIC struct FileNode *FindFileNode(STRPTR name, struct FileNode *skip);
179 STATIC struct LockNode *FindLockNode(STRPTR name, struct LockNode *skip);
180 STATIC LONG CheckAccessModeCollision(STRPTR name, LONG mode);
181 STATIC LONG NameAlreadyInUse(STRPTR name);
182 STATIC BOOL IsReservedName(STRPTR name);
183 STATIC LONG MapErrnoToIoErr(int error);
184 STATIC VOID TranslateBName(UBYTE *name, UBYTE *map);
185 STATIC VOID Cleanup(VOID);
186 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, LONG *opt_dst_offset, STRPTR device_name, STRPTR volume_name, STRPTR translation_file);
187 STATIC VOID ConvertBString(LONG max_len, STRPTR cstring, APTR bstring);
188 STATIC BPTR Action_Parent(struct FileLock *parent, SIPTR *error_ptr);
189 STATIC LONG Action_DeleteObject(struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
190 STATIC BPTR Action_CreateDir(struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
191 STATIC BPTR Action_LocateObject(struct FileLock *parent, APTR bcpl_name, LONG mode, SIPTR *error_ptr);
192 STATIC BPTR Action_CopyDir(struct FileLock *lock, SIPTR *error_ptr);
193 STATIC LONG Action_FreeLock(struct FileLock *lock, SIPTR *error_ptr);
194 STATIC LONG Action_SameLock(struct FileLock *lock1, struct FileLock *lock2, SIPTR *error_ptr);
195 STATIC LONG Action_SetProtect(struct FileLock *parent, APTR bcpl_name, LONG mask, SIPTR *error_ptr);
196 STATIC LONG Action_RenameObject(struct FileLock *source_lock, APTR source_bcpl_name, struct FileLock *destination_lock, APTR destination_bcpl_name, SIPTR *error_ptr);
197 STATIC LONG Action_DiskInfo(struct InfoData *id, SIPTR *error_ptr);
198 STATIC LONG Action_Info(struct FileLock *lock, struct InfoData *id, SIPTR *error_ptr);
199 STATIC LONG Action_ExamineObject(struct FileLock *lock, struct FileInfoBlock *fib, SIPTR *error_ptr);
200 STATIC BOOL NameIsAcceptable(STRPTR name, LONG max_len);
201 STATIC LONG Action_ExamineNext(struct FileLock *lock, struct FileInfoBlock *fib, SIPTR *error_ptr);
202 STATIC LONG Action_ExamineAll(struct FileLock *lock, struct ExAllData *ed, ULONG size, ULONG type, struct ExAllControl *eac, SIPTR *error_ptr);
203 STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
204 STATIC LONG Action_Read(struct FileNode *fn, APTR mem, LONG length, SIPTR *error_ptr);
205 STATIC LONG Action_Write(struct FileNode *fn, APTR mem, LONG length, SIPTR *error_ptr);
206 STATIC LONG Action_End(struct FileNode *fn, SIPTR *error_ptr);
207 STATIC LONG Action_Seek(struct FileNode *fn, LONG position, LONG mode, SIPTR *error_ptr);
208 STATIC LONG Action_SetFileSize(struct FileNode *fn, LONG position, LONG mode, SIPTR *error_ptr);
209 STATIC LONG Action_SetDate(struct FileLock *parent, APTR bcpl_name, struct DateStamp *ds, SIPTR *error_ptr);
210 STATIC LONG Action_ExamineFH(struct FileNode *fn, struct FileInfoBlock *fib, SIPTR *error_ptr);
211 STATIC BPTR Action_ParentFH(struct FileNode *fn, SIPTR *error_ptr);
212 STATIC BPTR Action_CopyDirFH(struct FileNode *fn, SIPTR *error_ptr);
213 STATIC LONG Action_FHFromLock(struct FileHandle *fh, struct FileLock *fl, SIPTR *error_ptr);
214 STATIC LONG Action_RenameDisk(APTR bcpl_name, SIPTR *error_ptr);
215 STATIC LONG Action_ChangeMode(LONG type, APTR object, LONG new_mode, SIPTR *error_ptr);
216 STATIC LONG Action_WriteProtect(LONG flag, ULONG key, SIPTR *error_ptr);
217 STATIC LONG Action_MoreCache(LONG buffer_delta, SIPTR *error_ptr);
218 STATIC LONG Action_SetComment(struct FileLock *parent, APTR bcpl_name, APTR bcpl_comment, SIPTR *error_ptr);
219 STATIC LONG Action_LockRecord(struct FileNode *fn, LONG offset, LONG length, LONG mode, ULONG timeout, SIPTR *error_ptr);
220 STATIC LONG Action_FreeRecord(struct FileNode *fn, LONG offset, LONG length, SIPTR *error_ptr);
221 STATIC VOID HandleFileSystem(STRPTR device_name, STRPTR volume_name, STRPTR service_name);
223 /****************************************************************************/
225 #if !defined(__AROS__)
226 struct Library * SysBase;
227 #endif
228 struct Library * DOSBase;
229 struct Library * UtilityBase;
230 struct Library * IntuitionBase;
231 struct Library * SocketBase;
232 struct Library * LocaleBase;
233 struct Library * TimerBase;
234 struct Library * IconBase;
236 /****************************************************************************/
238 #if defined(__amigaos4__)
240 /****************************************************************************/
242 struct ExecIFace * IExec;
243 struct DOSIFace * IDOS;
244 struct UtilityIFace * IUtility;
245 struct IntuitionIFace * IIntuition;
246 struct SocketIFace * ISocket;
247 struct LocaleIFace * ILocale;
248 struct TimerIFace * ITimer;
249 struct IconIFace * IIcon;
251 /****************************************************************************/
253 #endif /* __amigaos4__ */
255 /****************************************************************************/
257 struct timerequest TimerRequest;
259 /****************************************************************************/
261 struct Locale * Locale;
263 /****************************************************************************/
265 #ifndef h_errno
266 int h_errno;
267 #endif
269 /****************************************************************************/
271 STATIC struct DosList * DeviceNode;
272 STATIC BOOL DeviceNodeAdded;
273 STATIC struct DosList * VolumeNode;
274 STATIC BOOL VolumeNodeAdded;
275 STATIC struct MsgPort * FileSystemPort;
277 STATIC smba_server_t * ServerData;
279 STATIC BOOL Quit;
280 STATIC BOOL Quiet;
281 STATIC BOOL CaseSensitive;
282 STATIC BOOL OmitHidden;
284 STATIC LONG DSTOffset;
285 STATIC LONG TimeZoneOffset;
286 STATIC BOOL OverrideLocaleTimeZone;
288 STATIC BOOL WriteProtected;
289 STATIC ULONG WriteProtectKey;
291 STATIC struct MinList FileList;
292 STATIC struct MinList LockList;
294 STATIC APTR MemoryPool;
296 STATIC struct RDArgs * Parameters;
297 STATIC struct DiskObject * Icon;
299 STATIC struct WBStartup * WBStartup;
301 STATIC struct MinList ErrorList;
303 STATIC STRPTR NewProgramName;
305 STATIC BOOL TranslateNames;
306 STATIC UBYTE A2M[256];
307 STATIC UBYTE M2A[256];
309 /****************************************************************************/
311 #if !defined(__AROS__)
312 LONG _start(VOID)
313 #else
314 int main(void)
315 #endif
317 struct
319 KEY Workgroup;
320 KEY UserName;
321 KEY Password;
322 SWITCH ChangeCase;
323 SWITCH CaseSensitive;
324 SWITCH OmitHidden;
325 SWITCH Quiet;
326 KEY ClientName;
327 KEY ServerName;
328 KEY DeviceName;
329 KEY VolumeName;
330 NUMBER CacheSize;
331 NUMBER DebugLevel;
332 NUMBER TimeZoneOffset;
333 NUMBER DSTOffset;
334 KEY TranslationFile;
335 KEY Service;
336 } args;
338 STRPTR cmd_template =
339 "DOMAIN=WORKGROUP/K,"
340 "USER=USERNAME/K,"
341 "PASSWORD/K,"
342 "CHANGECASE/S,"
343 "CASE=CASESENSITIVE/S,"
344 "OMITHIDDEN/S,"
345 "QUIET/S,"
346 "CLIENT=CLIENTNAME/K,"
347 "SERVER=SERVERNAME/K,"
348 "DEVICE=DEVICENAME/K,"
349 "VOLUME=VOLUMENAME/K,"
350 "CACHE=CACHESIZE/N/K,"
351 "DEBUGLEVEL=DEBUG/N/K,"
352 "TZ=TIMEZONEOFFSET/N/K,"
353 "DST=DSTOFFSET/N/K,"
354 "TRANSLATE=TRANSLATIONFILE/K,"
355 "SERVICE/A";
357 struct Process * this_process;
358 UBYTE program_name[MAX_FILENAME_LEN];
359 LONG result = RETURN_FAIL;
360 LONG number;
361 LONG other_number;
362 LONG cache_size = 0;
363 char env_workgroup_name[17];
364 char env_user_name[64];
365 char env_password[64];
367 #if !defined(__AROS__)
368 SysBase = (struct Library *)AbsExecBase;
370 #if defined(__amigaos4__)
372 IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
374 #endif /* __amigaos4__ */
375 #endif
376 /* Pick up the Workbench startup message, if
377 * there is one.
379 this_process = (struct Process *)FindTask(NULL);
380 if(this_process->pr_CLI == ZERO)
382 WaitPort(&this_process->pr_MsgPort);
383 WBStartup = (struct WBStartup *)GetMsg(&this_process->pr_MsgPort);
385 else
387 WBStartup = NULL;
390 /* Don't emit any debugging output before we are ready. */
391 SETDEBUGLEVEL(0);
393 /* Open the libraries we need and check
394 * whether we could get them.
396 DOSBase = OpenLibrary("dos.library",0);
398 #if defined(__amigaos4__)
400 if(DOSBase != NULL)
402 IDOS = (struct DOSIFace *)GetInterface(DOSBase, "main", 1, 0);
403 if(IDOS == NULL)
405 CloseLibrary(DOSBase);
406 DOSBase = NULL;
410 #endif /* __amigaos4__ */
412 UtilityBase = OpenLibrary("utility.library",37);
414 #if defined(__amigaos4__)
416 if(UtilityBase != NULL)
418 IUtility = (struct UtilityIFace *)GetInterface(UtilityBase, "main", 1, 0);
419 if(IUtility == NULL)
421 CloseLibrary(UtilityBase);
422 UtilityBase = NULL;
426 #endif /* __amigaos4__ */
428 if(UtilityBase == NULL || DOSBase == NULL || DOSBase->lib_Version < MINIMUM_OS_VERSION)
430 /* Complain loudly if this is not the operating
431 * system version we expected.
433 if(DOSBase != NULL && this_process->pr_CLI != ZERO)
435 STRPTR msg;
437 #if (MINIMUM_OS_VERSION < 39)
439 msg = "AmigaOS 2.04 or higher required.\n";
441 #else
443 msg = "AmigaOS 3.0 or higher required.\n";
445 #endif /* MINIMUM_OS_VERSION */
447 Write(Output(),msg,strlen(msg));
450 goto out;
453 /* This needs to be set up properly for ReportError()
454 * to work.
456 NewList((struct List *)&ErrorList);
458 memset(&args,0,sizeof(args));
460 /* If this program was launched from Workbench,
461 * parameter passing will have to be handled
462 * differently.
464 if(WBStartup != NULL)
466 STRPTR str;
467 BPTR old_dir;
468 LONG n;
470 if(WBStartup->sm_NumArgs > 1)
471 n = 1;
472 else
473 n = 0;
475 /* Get the name of the program, as it was launched
476 * from Workbench. We actually prefer the name of
477 * the first project file, if there is one.
479 strlcpy(program_name,WBStartup->sm_ArgList[n].wa_Name,sizeof(program_name));
481 /* Now open icon.library and read that icon. */
482 IconBase = OpenLibrary("icon.library",0);
484 #if defined(__amigaos4__)
486 if(IconBase != NULL)
488 IIcon = (struct IconIFace *)GetInterface(IconBase, "main", 1, 0);
489 if(IIcon == NULL)
491 CloseLibrary(IconBase);
492 IconBase = NULL;
496 #endif /* __amigaos4__ */
498 if(IconBase == NULL)
500 ReportError("Could not open 'icon.library'.");
501 goto out;
504 old_dir = CurrentDir(WBStartup->sm_ArgList[n].wa_Lock);
505 Icon = GetDiskObject(WBStartup->sm_ArgList[n].wa_Name);
506 CurrentDir(old_dir);
508 if(Icon == NULL)
510 ReportError("Icon not found.");
511 goto out;
514 /* Only input validation errors are reported below. */
515 result = RETURN_ERROR;
517 /* Examine the icon's tool types and use the
518 * information to fill the startup parameter
519 * data structure.
521 str = FindToolType(Icon->do_ToolTypes,"DOMAIN");
522 if(str == NULL)
523 str = FindToolType(Icon->do_ToolTypes,"WORKGROUP");
525 if(str == NULL)
527 if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
528 GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
530 str = env_workgroup_name;
532 else
534 ReportError("Required 'WORKGROUP' parameter was not provided.");
535 goto out;
539 args.Workgroup = str;
541 str = FindToolType(Icon->do_ToolTypes,"USER");
542 if(str == NULL)
543 str = FindToolType(Icon->do_ToolTypes,"USERNAME");
545 if(str == NULL)
547 if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
548 GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
550 str = env_user_name;
554 args.UserName = str;
556 str = FindToolType(Icon->do_ToolTypes,"PASSWORD");
557 if(str == NULL)
559 if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
560 str = env_password;
563 args.Password = str;
565 if(FindToolType(Icon->do_ToolTypes,"CHANGECASE") != NULL)
566 args.ChangeCase = TRUE;
568 if(FindToolType(Icon->do_ToolTypes,"OMITHIDDEN") != NULL)
569 args.OmitHidden = TRUE;
571 if(FindToolType(Icon->do_ToolTypes,"QUIET") != NULL)
572 args.Quiet = TRUE;
574 if(FindToolType(Icon->do_ToolTypes,"CASE") != NULL ||
575 FindToolType(Icon->do_ToolTypes,"CASESENSITIVE") != NULL)
577 args.CaseSensitive = TRUE;
580 str = FindToolType(Icon->do_ToolTypes,"CLIENT");
581 if(str == NULL)
582 str = FindToolType(Icon->do_ToolTypes,"CLIENTNAME");
584 args.ClientName = str;
586 str = FindToolType(Icon->do_ToolTypes,"SERVER");
587 if(str == NULL)
588 str = FindToolType(Icon->do_ToolTypes,"SERVERNAME");
590 args.ServerName = str;
592 str = FindToolType(Icon->do_ToolTypes,"DEVICE");
593 if(str == NULL)
594 str = FindToolType(Icon->do_ToolTypes,"DEVICENAME");
596 args.DeviceName = str;
598 str = FindToolType(Icon->do_ToolTypes,"VOLUME");
599 if(str == NULL)
600 str = FindToolType(Icon->do_ToolTypes,"VOLUMENAME");
602 args.VolumeName = str;
604 str = FindToolType(Icon->do_ToolTypes,"TRANSLATE");
605 if(str == NULL)
606 str = FindToolType(Icon->do_ToolTypes,"TRANSLATIONFILE");
608 args.TranslationFile = str;
610 str = FindToolType(Icon->do_ToolTypes,"SERVICE");
611 args.Service = str;
613 if(str != NULL)
615 /* Set up the name of the program, as it will be
616 * displayed in error requesters.
618 NewProgramName = AllocVec(strlen(WBStartup->sm_ArgList[0].wa_Name) + strlen(" ''") + strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
619 if(NewProgramName != NULL)
620 SPrintf(NewProgramName,"%s '%s'",WBStartup->sm_ArgList[0].wa_Name,str);
623 str = FindToolType(Icon->do_ToolTypes,"DEBUG");
624 if(str == NULL)
625 str = FindToolType(Icon->do_ToolTypes,"DEBUGLEVEL");
627 if(str != NULL)
629 if(StrToLong(str,&number) == -1)
631 ReportError("Invalid number '%s' for 'DEBUG' parameter.",str);
632 goto out;
635 args.DebugLevel = &number;
638 str = FindToolType(Icon->do_ToolTypes,"TZ");
639 if(str == NULL)
640 str = FindToolType(Icon->do_ToolTypes,"TIMEZONEOFFSET");
642 if(str != NULL)
644 if(StrToLong(str,&other_number) == -1)
646 ReportError("Invalid number '%s' for 'TIMEZONEOFFSET' parameter.",str);
647 goto out;
650 args.TimeZoneOffset = &other_number;
653 str = FindToolType(Icon->do_ToolTypes,"DST");
654 if(str == NULL)
655 str = FindToolType(Icon->do_ToolTypes,"DSTOFFSET");
657 if(str != NULL)
659 if(StrToLong(str,&other_number) == -1)
661 ReportError("Invalid number '%s' for 'DSTOFFSET' parameter.",str);
662 goto out;
665 args.DSTOffset = &other_number;
668 str = FindToolType(Icon->do_ToolTypes,"CACHE");
669 if(str == NULL)
670 str = FindToolType(Icon->do_ToolTypes,"CACHESIZE");
672 if(str != NULL)
674 if(StrToLong(str,&number) == -1)
676 ReportError("Invalid number '%s' for 'CACHE' parameter.",str);
677 goto out;
680 cache_size = number;
683 if(args.Workgroup == NULL)
685 ReportError("Required 'WORKGROUP' parameter was not provided.");
686 goto out;
689 if(args.Service == NULL)
691 ReportError("'SERVICE' parameter needs an argument.");
692 goto out;
695 else
697 /* Only input validation errors are reported below. */
698 result = RETURN_ERROR;
700 GetProgramName(program_name,sizeof(program_name));
702 Parameters = ReadArgs(cmd_template,(IPTR *)&args,NULL);
703 if(Parameters == NULL)
705 PrintFault(IoErr(),FilePart(program_name));
706 goto out;
709 if(args.Workgroup == NULL)
711 if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
712 GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
714 args.Workgroup = env_workgroup_name;
716 else
718 ReportError("Required 'WORKGROUP' parameter was not provided.");
719 goto out;
723 if(args.UserName == NULL)
725 if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
726 GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
728 args.UserName = env_user_name;
732 if(args.Password == NULL)
734 if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
735 args.Password = env_password;
738 if(args.Service != NULL)
740 STRPTR name = FilePart(program_name);
742 /* Set up the name of the program, as it will be
743 * displayed in the proces status list.
745 NewProgramName = AllocVec(strlen(name) + strlen(" ''") + strlen(args.Service)+1,MEMF_ANY|MEMF_PUBLIC);
746 if(NewProgramName != NULL)
747 SPrintf(NewProgramName,"%s '%s'",name,args.Service);
750 if(args.CacheSize != NULL)
751 cache_size = (*args.CacheSize);
754 /* Use the default if no user name is given. */
755 if(args.UserName == NULL)
756 args.UserName = "GUEST";
758 /* Use the default if no device or volume name is given. */
759 if(args.DeviceName == NULL && args.VolumeName == NULL)
760 args.DeviceName = "SMBFS";
762 CaseSensitive = (BOOL)args.CaseSensitive;
763 OmitHidden = (BOOL)args.OmitHidden;
765 /* Configure the debugging options. */
766 SETPROGRAMNAME(FilePart(program_name));
768 if(args.DebugLevel != NULL)
769 SETDEBUGLEVEL(*args.DebugLevel);
770 else
771 SETDEBUGLEVEL(0);
773 D(("%s (%s)",VERS,DATE));
775 if(Setup(
776 FilePart(program_name),
777 args.Service,
778 args.Workgroup,
779 args.UserName,
780 args.Password,
781 args.ChangeCase,
782 args.ClientName,
783 args.ServerName,
784 cache_size,
785 args.TimeZoneOffset,
786 args.DSTOffset,
787 args.DeviceName,
788 args.VolumeName,
789 args.TranslationFile))
791 Quiet = args.Quiet;
793 if(Locale != NULL)
794 SHOWVALUE(Locale->loc_GMTOffset);
796 HandleFileSystem(args.DeviceName,args.VolumeName,args.Service);
798 result = RETURN_WARN;
800 else
802 result = RETURN_ERROR;
805 out:
807 Cleanup();
809 return(result);
812 /****************************************************************************/
814 #ifdef __AROS__
815 #define LocalPrintf(format,args...) Printf(format ,##args )
816 #else
817 LONG VARARGS68K
818 LocalPrintf(STRPTR format, ...)
820 va_list args;
821 LONG result;
823 #if defined(__amigaos4__)
825 va_startlinear(args,format);
826 result = VPrintf(format,va_getlinearva(args,APTR));
827 va_end(args);
829 #else
831 va_start(args,format);
832 result = VPrintf(format,args);
833 va_end(args);
835 #endif /* __amigaos4__ */
837 return(result);
839 #endif /* __AROS__ */
841 /****************************************************************************/
843 /* Obtain the descriptive text corresponding to an error number
844 * that may have been generated by the TCP/IP stack.
846 STRPTR
847 amitcp_strerror(int error)
849 struct TagItem tags[2];
850 STRPTR result;
852 ENTER();
854 tags[0].ti_Tag = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
855 tags[0].ti_Data = error;
856 tags[1].ti_Tag = TAG_END;
858 SocketBaseTagList(tags);
860 result = (STRPTR)tags[0].ti_Data;
862 RETURN(result);
863 return(result);
866 /****************************************************************************/
868 /* Return the descriptive text associated with a host lookup failure code. */
869 STRPTR
870 host_strerror(int error)
872 struct TagItem tags[2];
873 STRPTR result;
875 ENTER();
877 tags[0].ti_Tag = SBTM_GETVAL(SBTC_HERRNOSTRPTR);
878 tags[0].ti_Data = error;
879 tags[1].ti_Tag = TAG_END;
881 SocketBaseTagList(tags);
883 result = (STRPTR)tags[0].ti_Data;
885 RETURN(result);
886 return(result);
889 /****************************************************************************/
891 /* Compare two strings, either case sensitive or not
892 * sensitive to the case of the letters. How this is
893 * to be done is controlled by a global option. This
894 * routine is called whenever two SMB file names are
895 * to be compared.
897 LONG
898 CompareNames(STRPTR a,STRPTR b)
900 LONG result;
902 if(CaseSensitive)
903 result = strcmp(a,b);
904 else
905 result = Stricmp(a,b);
907 return(result);
910 /****************************************************************************/
912 /* Translate a string into all upper case characters. */
913 VOID
914 StringToUpper(STRPTR s)
916 UBYTE c;
918 while((c = (*s)) != '\0')
919 (*s++) = ToUpper(c);
922 /****************************************************************************/
924 /* Prepare the accumulated list of error messages for display
925 * and purge the contents of that list.
927 STATIC VOID
928 DisplayErrorList(VOID)
930 struct MinNode * last = NULL;
931 struct MinNode * mn;
932 STRPTR str = NULL;
933 STRPTR msg;
934 LONG len;
936 /* Determine how much memory will have to be
937 * allocated to hold all the accumulated
938 * error messages.
940 len = 0;
942 for(mn = ErrorList.mlh_Head ;
943 mn->mln_Succ != NULL ;
944 mn = mn->mln_Succ)
946 last = mn;
948 msg = (STRPTR)(mn + 1);
950 len += strlen(msg)+1;
953 /* Allocate the memory for the messages, then
954 * copy them there.
956 if(len > 0)
958 str = AllocVec(len,MEMF_ANY);
959 if(str != NULL)
961 str[0] = '\0';
963 for(mn = ErrorList.mlh_Head ;
964 mn->mln_Succ != NULL ;
965 mn = mn->mln_Succ)
967 msg = (STRPTR)(mn + 1);
969 strcat(str,msg);
970 if(mn != last)
971 strcat(str,"\n");
976 /* Purge the list. */
977 while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
978 FreeVec(mn);
980 /* Display the error messages. */
981 if(str != NULL)
983 IntuitionBase = OpenLibrary("intuition.library",37);
985 #if defined(__amigaos4__)
987 if(IntuitionBase != NULL)
989 IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, "main", 1, 0);
990 if(IIntuition == NULL)
992 CloseLibrary(IntuitionBase);
993 IntuitionBase = NULL;
997 #endif /* __amigaos4__ */
999 if(IntuitionBase != NULL)
1001 struct EasyStruct es;
1002 STRPTR title;
1004 memset(&es,0,sizeof(es));
1006 if(NewProgramName == NULL)
1007 title = WBStartup->sm_ArgList[0].wa_Name;
1008 else
1009 title = NewProgramName;
1011 es.es_StructSize = sizeof(es);
1012 es.es_Title = title;
1013 es.es_TextFormat = str;
1014 es.es_GadgetFormat = "Ok";
1016 EasyRequestArgs(NULL,&es,NULL,NULL);
1019 FreeVec(str);
1022 #if defined(__amigaos4__)
1024 if(IIntuition != NULL)
1026 DropInterface((struct Interface *)IIntuition);
1027 IIntuition = NULL;
1030 #endif /* __amigaos4__ */
1032 CloseLibrary(IntuitionBase);
1033 IntuitionBase = NULL;
1036 /* Add another error message to the list; the messages are
1037 * collected so that they may be displayed together when
1038 * necessary.
1040 STATIC VOID
1041 AddError(STRPTR fmt,APTR args)
1043 LONG len;
1045 len = CVSPrintf(fmt,args);
1046 if(len > 0)
1048 struct MinNode * mn;
1050 mn = AllocVec(sizeof(*mn) + len,MEMF_ANY|MEMF_PUBLIC);
1051 if(mn != NULL)
1053 STRPTR msg = (STRPTR)(mn + 1);
1055 VSPrintf(msg,fmt,args);
1057 AddTail((struct List *)&ErrorList,(struct Node *)mn);
1062 /****************************************************************************/
1064 /* Report an error that has occured; if the program was not launched
1065 * from Shell, error messages will be accumulated for later display.
1067 #ifdef __AROS__
1068 VOID VReportError(STRPTR fmt, IPTR *args)
1070 if(NOT Quiet)
1072 if(WBStartup != NULL)
1074 AddError(fmt,args);
1076 else
1078 UBYTE program_name[MAX_FILENAME_LEN];
1080 GetProgramName(program_name,sizeof(program_name));
1082 LocalPrintf("%s: ",FilePart(program_name));
1084 VPrintf(fmt,args);
1086 LocalPrintf("\n");
1090 #else
1091 VOID VARARGS68K
1092 ReportError(STRPTR fmt,...)
1094 if(NOT Quiet)
1096 va_list args;
1098 if(WBStartup != NULL)
1100 #if defined(__amigaos4__)
1102 va_startlinear(args,fmt);
1103 AddError(fmt,va_getlinearva(args,APTR));
1104 va_end(args);
1106 #else
1108 va_start(args,fmt);
1109 AddError(fmt,args);
1110 va_end(args);
1112 #endif /* __amigaos4__ */
1114 else
1116 UBYTE program_name[MAX_FILENAME_LEN];
1118 GetProgramName(program_name,sizeof(program_name));
1120 LocalPrintf("%s: ",FilePart(program_name));
1122 #if defined(__amigaos4__)
1124 va_startlinear(args,fmt);
1125 VPrintf(fmt,va_getlinearva(args,APTR));
1126 va_end(args);
1128 #else
1130 va_start(args,fmt);
1131 VPrintf(fmt,args);
1132 va_end(args);
1134 #endif /* __amigaos4__ */
1136 LocalPrintf("\n");
1140 #endif
1142 /****************************************************************************/
1144 /* Release memory allocated from the global pool. */
1145 VOID
1146 FreeMemory(APTR address)
1148 if(address != NULL)
1150 ULONG * mem = address;
1152 #if DEBUG
1154 if(GETDEBUGLEVEL() > 0)
1155 memset(address,0xA3,mem[-1] - sizeof(*mem));
1157 #endif /* DEBUG */
1159 FreePooled(MemoryPool,&mem[-1],mem[-1]);
1163 /* Allocate memory from the global pool. */
1164 APTR
1165 AllocateMemory(ULONG size)
1167 APTR result = NULL;
1169 if(size > 0)
1171 ULONG * mem;
1173 size = (sizeof(*mem) + size + 7) & ~7UL;
1175 mem = AllocPooled(MemoryPool,size);
1176 if(mem != NULL)
1178 (*mem++) = size;
1180 #if DEBUG
1182 if(GETDEBUGLEVEL() > 0)
1183 memset(mem,0xA5,mem[-1] - sizeof(*mem));
1185 #endif /* DEBUG */
1187 result = mem;
1191 return(result);
1194 /****************************************************************************/
1196 /* Obtain the number of seconds to add to the current time
1197 * to translate local time into UTC.
1199 LONG
1200 GetTimeZoneDelta(VOID)
1202 LONG seconds;
1204 if(OverrideLocaleTimeZone)
1206 seconds = 60 * TimeZoneOffset;
1208 else if (Locale != NULL)
1210 /* The GMT offset actually is the number of minutes to add to
1211 * the local time to yield Greenwich Mean Time. It is negative
1212 * for all time zones east of the Greenwich meridian and
1213 * positive for all time zones west of it.
1215 seconds = 60 * Locale->loc_GMTOffset;
1217 else
1219 seconds = 0;
1222 return(seconds + DSTOffset);
1225 /****************************************************************************/
1227 /* Obtain the current time, in standard Unix format, adjusted for the
1228 * local time zone.
1230 ULONG
1231 GetCurrentTime(VOID)
1233 struct timeval tv;
1234 ULONG result;
1236 GetSysTime((APTR)&tv);
1238 result = UNIX_TIME_OFFSET + GetTimeZoneDelta() + tv.tv_secs;
1240 return(result);
1243 /****************************************************************************/
1245 /* Fill in a 'tm' type time specification with time information
1246 * corresponding to the number of seconds provided. Input is
1247 * in Unix format.
1249 VOID
1250 GMTime(time_t seconds,struct tm * tm)
1252 struct ClockData clock_data;
1254 if(seconds < UNIX_TIME_OFFSET)
1255 seconds = 0;
1256 else
1257 seconds -= UNIX_TIME_OFFSET;
1259 Amiga2Date(seconds,&clock_data);
1261 memset(tm,0,sizeof(*tm));
1263 tm->tm_sec = clock_data.sec;
1264 tm->tm_min = clock_data.min;
1265 tm->tm_hour = clock_data.hour;
1266 tm->tm_mday = clock_data.mday;
1267 tm->tm_mon = clock_data.month - 1;
1268 tm->tm_year = clock_data.year - 1900;
1271 /* Calculate the number of seconds that have passed since January 1st 1970
1272 * based upon the time specification provided. Output is in Unix format.
1274 time_t
1275 MakeTime(const struct tm * const tm)
1277 struct ClockData clock_data;
1278 time_t seconds;
1280 clock_data.sec = tm->tm_sec;
1281 clock_data.min = tm->tm_min;
1282 clock_data.hour = tm->tm_hour;
1283 clock_data.mday = tm->tm_mday;
1284 clock_data.month = tm->tm_mon + 1;
1285 clock_data.year = tm->tm_year + 1900;
1287 seconds = Date2Amiga(&clock_data) + UNIX_TIME_OFFSET;
1289 return(seconds);
1292 /****************************************************************************/
1294 struct FormatContext
1296 UBYTE * fc_Buffer;
1297 LONG fc_Size;
1300 /****************************************************************************/
1302 #if !defined(__AROS__)
1303 STATIC VOID ASM
1304 CountChar(REG(a3,struct FormatContext * fc))
1305 #else
1306 STATIC VOID CountChar(struct FormatContext * fc)
1307 #endif
1309 fc->fc_Size++;
1312 /* Count the number of characters SPrintf() would put into a string. */
1313 STATIC LONG
1314 CVSPrintf(STRPTR format_string,APTR args)
1316 struct FormatContext fc;
1318 fc.fc_Size = 0;
1320 RawDoFmt((STRPTR)format_string,args,(VOID (*)())CountChar,&fc);
1322 return(fc.fc_Size);
1325 /****************************************************************************/
1327 #if !defined(__AROS__)
1328 STATIC VOID ASM
1329 StuffChar(REG(d0,UBYTE c),REG(a3,struct FormatContext * fc))
1330 #else
1331 STATIC VOID StuffChar(UBYTE c, struct FormatContext * fc)
1332 #endif
1334 (*fc->fc_Buffer++) = c;
1337 STATIC VOID
1338 VSPrintf(STRPTR buffer, STRPTR formatString, APTR args)
1340 struct FormatContext fc;
1342 fc.fc_Buffer = buffer;
1344 RawDoFmt(formatString,args,(VOID (*)())StuffChar,&fc);
1347 /****************************************************************************/
1349 #if !defined(__AROS__)
1350 /* Format a string for output. */
1351 VOID VARARGS68K
1352 SPrintf(STRPTR buffer, STRPTR formatString,...)
1354 va_list varArgs;
1356 #if defined(__amigaos4__)
1358 va_startlinear(varArgs,formatString);
1359 VSPrintf(buffer,formatString,va_getlinearva(varArgs,APTR));
1360 va_end(varArgs);
1362 #else
1364 va_start(varArgs,formatString);
1365 VSPrintf(buffer,formatString,varArgs);
1366 va_end(varArgs);
1368 #endif /* __amigaos4__ */
1370 #endif
1372 /****************************************************************************/
1374 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
1375 * Thanks much, Chris!
1377 struct addr_entry
1379 unsigned short flags;
1380 unsigned char address[4];
1383 struct nmb_header
1385 unsigned short name_trn_id;
1386 unsigned short flags;
1387 unsigned short qdcount;
1388 unsigned short ancount;
1389 unsigned short nscount;
1390 unsigned short arcount;
1393 static UBYTE *
1394 L1_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx)
1396 int i = 0;
1397 int j = 0;
1398 int k;
1400 while(('\0' != name[i]) && (i < 15))
1402 k = ToUpper(name[i]);
1403 i++;
1404 dst[j++] = 'A' + ((k & 0xF0) >> 4);
1405 dst[j++] = 'A' + (k & 0x0F);
1408 i = 'A' + ((pad & 0xF0) >> 4);
1409 k = 'A' + (pad & 0x0F);
1411 while(j < 30)
1413 dst[j++] = i;
1414 dst[j++] = k;
1417 dst[30] = 'A' + ((sfx & 0xF0) >> 4);
1418 dst[31] = 'A' + (sfx & 0x0F);
1419 dst[32] = '\0';
1421 return(dst);
1424 static int
1425 L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, const UBYTE * scope)
1427 int lenpos;
1428 int i;
1429 int j;
1431 if(NULL == L1_Encode(&dst[1], name, pad, sfx))
1432 return(-1);
1434 dst[0] = 0x20;
1435 lenpos = 33;
1437 if('\0' != (*scope))
1441 for(i = 0, j = (lenpos + 1);
1442 ('.' != scope[i]) && ('\0' != scope[i]);
1443 i++, j++)
1445 dst[j] = ToUpper(scope[i]);
1448 dst[lenpos] = (UBYTE)i;
1449 lenpos += i + 1;
1450 scope += i;
1452 while('.' == (*scope++));
1454 dst[lenpos] = '\0';
1457 return(lenpos + 1);
1461 BroadcastNameQuery(char *name, char *scope, UBYTE *address)
1463 static const UBYTE header[12] =
1465 0x07, 0xB0, /* 1964 == 0x07B0. */
1466 0x01, 0x10, /* Binary 0 0000 0010001 0000 */
1467 0x00, 0x01, /* One name query. */
1468 0x00, 0x00, /* Zero answers. */
1469 0x00, 0x00, /* Zero authorities. */
1470 0x00, 0x00 /* Zero additional. */
1473 static const UBYTE query_tail[4] =
1475 0x00, 0x20,
1476 0x00, 0x01
1479 struct timeval tv;
1480 fd_set read_fds;
1481 int sock_fd;
1482 int option_true = 1;
1483 struct sockaddr_in sox;
1484 struct nmb_header nmb_header;
1485 UBYTE buffer[512];
1486 int total_len;
1487 int i,n;
1488 int result;
1489 struct servent * s;
1491 ENTER();
1493 sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
1494 if(sock_fd < 0)
1496 SHOWMSG("couldn't get the socket");
1497 result = (-errno);
1498 goto out;
1501 if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &option_true, sizeof(option_true)) < 0)
1503 SHOWMSG("couldn't enable the broadcast option");
1504 result = (-errno);
1505 goto out;
1508 sox.sin_family = AF_INET;
1509 sox.sin_addr.s_addr = htonl(0xFFFFFFFF);
1511 s = getservbyname("netbios-ns","udp");
1512 if(s != NULL)
1513 sox.sin_port = htons(s->s_port);
1514 else
1515 sox.sin_port = htons(137);
1517 memcpy(buffer, header, (total_len = sizeof(header)));
1519 n = L2_Encode(&buffer[total_len], name, ' ', '\0', scope);
1520 if(n < 0)
1522 SHOWMSG("name encoding failed");
1523 result = (-EINVAL);
1524 goto out;
1527 total_len += n;
1528 memcpy(&buffer[total_len], query_tail, sizeof(query_tail));
1529 total_len += sizeof(query_tail);
1531 result = (-ENOENT);
1532 n = 0;
1534 /* Send the query packet; retry five times with a one second
1535 * delay in between.
1537 for(i = 0 ; i < 5 ; i++)
1539 if(sendto(sock_fd, (void *) buffer, total_len, 0, (struct sockaddr *)&sox, sizeof(struct sockaddr_in)) < 0)
1541 SHOWMSG("could not send the packet");
1542 result = (-errno);
1543 goto out;
1546 /* Wait for a response to arrive. */
1547 tv.tv_secs = 1;
1548 tv.tv_micro = 0;
1550 FD_ZERO(&read_fds);
1551 FD_SET(sock_fd,&read_fds);
1553 if(WaitSelect(sock_fd+1, &read_fds, NULL, NULL, &tv, NULL) > 0)
1555 n = recvfrom(sock_fd, buffer, sizeof(buffer), 0, NULL, NULL);
1556 if(n < 0)
1558 SHOWMSG("could not pick up the response packet");
1559 result = (-errno);
1560 goto out;
1562 else if (n > 0)
1564 break;
1569 /* Did we get anything at all? */
1570 if(n > (int)sizeof(nmb_header))
1572 /* Check whether the query was successful. */
1573 memcpy(&nmb_header, buffer, sizeof(nmb_header));
1574 if((nmb_header.flags & 0xF) == OK)
1576 /* Find the NB/IP fields which directly follow
1577 * the name.
1579 for(i = sizeof(header) + strlen(&buffer[sizeof(header)])+1 ; i < n - (int)sizeof(query_tail) ; i++)
1581 if(memcmp(&buffer[i], query_tail, sizeof(query_tail)) == SAME)
1583 int start;
1585 /* This should be the start of the interesting bits;
1586 * we skip the NB/IP fields and the TTL field.
1588 start = i + sizeof(query_tail) + sizeof(long);
1589 if(start < n)
1591 unsigned short read_len;
1592 struct addr_entry addr_entry;
1594 /* This should be the read length. */
1595 memcpy(&read_len, &buffer[start], 2);
1597 /* Is there any useful and readable data attached? */
1598 if(read_len >= sizeof(addr_entry) &&
1599 start + (int)sizeof(read_len) + (int)sizeof(addr_entry) <= n)
1601 /* Copy a single address entry; this should be
1602 * just the one we need.
1604 memcpy(&addr_entry, &buffer[start + sizeof(read_len)], sizeof(addr_entry));
1606 /* Copy the address field (IPv4 only). */
1607 memcpy(address, addr_entry.address, 4);
1609 result = 0;
1613 break;
1619 out:
1621 if(sock_fd >= 0)
1622 CloseSocket(sock_fd);
1624 RETURN(result);
1625 return(result);
1628 /****************************************************************************/
1630 /* Send a disk change notification message which will be picked up
1631 * by all applications that listen for this kind of event, e.g.
1632 * Workbench.
1634 STATIC VOID
1635 SendDiskChange(ULONG class)
1637 struct IOStdReq * input_request = NULL;
1638 struct MsgPort * input_port;
1639 struct InputEvent ie;
1641 ENTER();
1643 input_port = CreateMsgPort();
1644 if(input_port == NULL)
1645 goto out;
1647 input_request = (struct IOStdReq *)CreateIORequest(input_port,sizeof(*input_request));
1648 if(input_request == NULL)
1649 goto out;
1651 if(OpenDevice("input.device",0,(struct IORequest *)input_request,0) != OK)
1652 goto out;
1654 memset(&ie,0,sizeof(ie));
1656 ie.ie_Class = class;
1657 ie.ie_Qualifier = IEQUALIFIER_MULTIBROADCAST;
1659 GetSysTime(&ie.ie_TimeStamp);
1661 input_request->io_Command = IND_WRITEEVENT;
1662 input_request->io_Data = &ie;
1663 input_request->io_Length = sizeof(ie);
1665 DoIO((struct IORequest *)input_request);
1667 out:
1669 if(input_request != NULL)
1671 if(input_request->io_Device != NULL)
1672 CloseDevice((struct IORequest *)input_request);
1674 DeleteIORequest((struct IORequest *)input_request);
1677 DeleteMsgPort(input_port);
1679 LEAVE();
1682 /****************************************************************************/
1684 /* Find the file node corresponding to a given name,
1685 * skipping a particular entry if necessary.
1687 STATIC struct FileNode *
1688 FindFileNode(STRPTR name,struct FileNode * skip)
1690 struct FileNode * result = NULL;
1691 struct FileNode * fn;
1693 for(fn = (struct FileNode *)FileList.mlh_Head ;
1694 fn->fn_MinNode.mln_Succ != NULL ;
1695 fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
1697 if(fn != skip && CompareNames(name,fn->fn_FullName) == SAME)
1699 result = fn;
1700 break;
1704 return(result);
1707 /* Find the lock node corresponding to a given name,
1708 * skipping a particular entry if necessary.
1710 STATIC struct LockNode *
1711 FindLockNode(STRPTR name,struct LockNode * skip)
1713 struct LockNode * result = NULL;
1714 struct LockNode * ln;
1716 for(ln = (struct LockNode *)LockList.mlh_Head ;
1717 ln->ln_MinNode.mln_Succ != NULL ;
1718 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
1720 if(ln != skip && CompareNames(name,ln->ln_FullName) == SAME)
1722 result = ln;
1723 break;
1727 return(result);
1730 /* Check whether a new reference to be made to a named
1731 * file will cause a conflict of access modes. No two
1732 * files and locks may refer to the same object if
1733 * either of these references is made in exclusive
1734 * mode. This is the case which this function is
1735 * trying to avoid.
1737 STATIC LONG
1738 CheckAccessModeCollision(STRPTR name,LONG mode)
1740 struct LockNode * ln;
1741 struct FileNode * fn;
1742 LONG error = OK;
1744 ENTER();
1745 SHOWSTRING(name);
1747 fn = FindFileNode(name,NULL);
1748 if(fn != NULL)
1750 if(mode != SHARED_LOCK || fn->fn_Mode != SHARED_LOCK)
1752 D(("collides with '%s'",fn->fn_FullName));
1753 error = ERROR_OBJECT_IN_USE;
1754 goto out;
1758 ln = FindLockNode(name,NULL);
1759 if(ln != NULL)
1761 if(mode != SHARED_LOCK || ln->ln_FileLock.fl_Access != SHARED_LOCK)
1763 D(("collides with '%s'",ln->ln_FullName));
1764 error = ERROR_OBJECT_IN_USE;
1765 goto out;
1769 out:
1771 RETURN(error);
1772 return(error);
1775 /* Find out whether there already exists a reference to a
1776 * certain file or directory.
1778 STATIC LONG
1779 NameAlreadyInUse(STRPTR name)
1781 LONG error = OK;
1783 ENTER();
1785 if(FindFileNode(name,NULL) != NULL)
1787 error = ERROR_OBJECT_IN_USE;
1788 goto out;
1791 if(FindLockNode(name,NULL) != NULL)
1793 error = ERROR_OBJECT_IN_USE;
1794 goto out;
1797 out:
1799 RETURN(error);
1800 return(error);
1803 /* Check whether an Amiga file name uses special characters which
1804 * should be avoided when used with the SMB file sharing protocol.
1806 STATIC BOOL
1807 IsReservedName(STRPTR name)
1809 BOOL result = FALSE;
1811 /* Disallow "." and "..". */
1812 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
1814 result = TRUE;
1816 else
1818 UBYTE c;
1820 /* Disallow the use of the backslash in file names. */
1821 while((c = (*name++)) != '\0')
1823 if(c == SMB_PATH_SEPARATOR)
1825 result = TRUE;
1826 break;
1831 return(result);
1834 /****************************************************************************/
1836 /* Convert a POSIX error code into an AmigaDOS error code. */
1837 STATIC LONG
1838 MapErrnoToIoErr(int error)
1840 /* Not all of these mappings make good sense; bear in mind that
1841 * POSIX covers more than a hundred different error codes
1842 * whereas with AmigaDOS we're stranded with a measly 48...
1844 STATIC const LONG Map[][2] =
1846 { EPERM, ERROR_OBJECT_NOT_FOUND }, /* Operation not permitted */
1847 { ENOENT, ERROR_OBJECT_NOT_FOUND }, /* No such file or directory */
1848 { ESRCH, ERROR_OBJECT_NOT_FOUND }, /* No such process */
1849 { EINTR, ERROR_BREAK }, /* Interrupted system call */
1850 { EIO, ERROR_OBJECT_IN_USE }, /* Input/output error */
1851 { E2BIG, ERROR_TOO_MANY_ARGS }, /* Argument list too long */
1852 { EBADF, ERROR_INVALID_LOCK }, /* Bad file descriptor */
1853 { ENOMEM, ERROR_NO_FREE_STORE }, /* Cannot allocate memory */
1854 { EACCES, ERROR_OBJECT_IN_USE }, /* Permission denied */
1855 #ifdef ENOTBLK
1856 { ENOTBLK, ERROR_OBJECT_WRONG_TYPE }, /* Block device required */
1857 #endif
1858 { EBUSY, ERROR_OBJECT_IN_USE }, /* Device busy */
1859 { EEXIST, ERROR_OBJECT_EXISTS }, /* File exists */
1860 { EXDEV, ERROR_NOT_IMPLEMENTED }, /* Cross-device link */
1861 { ENOTDIR, ERROR_OBJECT_WRONG_TYPE }, /* Not a directory */
1862 { EISDIR, ERROR_OBJECT_WRONG_TYPE }, /* Is a directory */
1863 { EINVAL, ERROR_BAD_NUMBER }, /* Invalid argument */
1864 { EFBIG, ERROR_DISK_FULL }, /* File too large */
1865 { ENOSPC, ERROR_DISK_FULL }, /* No space left on device */
1866 { ESPIPE, ERROR_SEEK_ERROR }, /* Illegal seek */
1867 { EROFS, ERROR_WRITE_PROTECTED }, /* Read-only file system */
1868 { EMLINK, ERROR_TOO_MANY_LEVELS }, /* Too many links */
1869 { ENOTSOCK, ERROR_OBJECT_WRONG_TYPE }, /* Socket operation on non-socket */
1870 { EDESTADDRREQ, ERROR_REQUIRED_ARG_MISSING }, /* Destination address required */
1871 { EMSGSIZE, ERROR_LINE_TOO_LONG }, /* Message too long */
1872 { EPROTOTYPE, ERROR_BAD_TEMPLATE }, /* Protocol wrong type for socket */
1873 { ENOPROTOOPT, ERROR_NOT_IMPLEMENTED }, /* Protocol not available */
1874 { EPROTONOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Protocol not supported */
1875 { ESOCKTNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Socket type not supported */
1876 { EOPNOTSUPP, ERROR_NOT_IMPLEMENTED }, /* Operation not supported */
1877 { EPFNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Protocol family not supported */
1878 { EAFNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Address family not supported by protocol family */
1879 { EADDRINUSE, ERROR_OBJECT_IN_USE }, /* Address already in use */
1880 { EADDRNOTAVAIL, ERROR_OBJECT_NOT_FOUND }, /* Can't assign requested address */
1881 { ENETDOWN, ERROR_OBJECT_NOT_FOUND }, /* Network is down */
1882 { ENETUNREACH, ERROR_OBJECT_NOT_FOUND }, /* Network is unreachable */
1883 { ENETRESET, ERROR_OBJECT_NOT_FOUND }, /* Network dropped connection on reset */
1884 { ECONNABORTED, ERROR_OBJECT_NOT_FOUND }, /* Software caused connection abort */
1885 { ECONNRESET, ERROR_OBJECT_NOT_FOUND }, /* Connection reset by peer */
1886 { ENOBUFS, ERROR_DISK_FULL }, /* No buffer space available */
1887 { EISCONN, ERROR_OBJECT_IN_USE }, /* Socket is already connected */
1888 { ENOTCONN, ERROR_OBJECT_WRONG_TYPE }, /* Socket is not connected */
1889 { ESHUTDOWN, ERROR_INVALID_LOCK }, /* Can't send after socket shutdown */
1890 { ECONNREFUSED, ERROR_OBJECT_IN_USE }, /* Connection refused */
1891 { ELOOP, ERROR_TOO_MANY_LEVELS }, /* Too many levels of symbolic links */
1892 { ENAMETOOLONG, ERROR_LINE_TOO_LONG }, /* File name too long */
1893 { EHOSTDOWN, ERROR_OBJECT_NOT_FOUND }, /* Host is down */
1894 { EHOSTUNREACH, ERROR_OBJECT_NOT_FOUND }, /* No route to host */
1895 { ENOTEMPTY, ERROR_DIRECTORY_NOT_EMPTY }, /* Directory not empty */
1896 { EPROCLIM, ERROR_TASK_TABLE_FULL }, /* Too many processes */
1897 #ifdef EUSERS
1898 { EUSERS, ERROR_TASK_TABLE_FULL }, /* Too many users */
1899 #endif
1900 { EDQUOT, ERROR_DISK_FULL }, /* Disc quota exceeded */
1901 { ENOLCK, ERROR_NOT_IMPLEMENTED }, /* no locks available */
1902 { -1, -1 }
1905 LONG result = ERROR_ACTION_NOT_KNOWN;
1906 LONG i;
1908 ENTER();
1910 if(error < 0)
1911 error = (-error);
1913 for(i = 0 ; Map[i][0] != -1 ; i++)
1915 if(Map[i][0] == error)
1917 result = Map[i][1];
1918 break;
1922 RETURN(result);
1923 return(result);
1926 /****************************************************************************/
1928 /* Translate a BCPL style file name (i.e. length is in the first byte)
1929 * via a mapping table.
1931 INLINE STATIC VOID
1932 TranslateBName(UBYTE * name,UBYTE * map)
1934 if(TranslateNames)
1936 LONG len;
1937 UBYTE c;
1939 #if !defined(__AROS__)
1940 len = (*name++);
1941 #else
1942 len = AROS_BSTR_strlen(name);
1943 name = AROS_BSTR_ADDR(name);
1944 #endif
1945 while(len-- > 0)
1947 c = (*name);
1949 (*name++) = map[c];
1954 /* Translate a NUL terminated file name via a mapping table. */
1955 INLINE STATIC VOID
1956 TranslateCName(UBYTE * name,UBYTE * map)
1958 if(TranslateNames)
1960 UBYTE c;
1962 while((c = (*name)) != '\0')
1963 (*name++) = map[c];
1967 /****************************************************************************/
1969 /* Remove a DosList entry using the proper protocols. Note that
1970 * this function can fail!
1972 STATIC BOOL
1973 ReallyRemoveDosEntry(struct DosList * entry)
1975 struct Message * mn;
1976 struct MsgPort * port;
1977 struct DosList * dl;
1978 BOOL result = FALSE;
1979 LONG kind,i;
1981 if(entry->dol_Type == DLT_DEVICE)
1982 kind = LDF_DEVICES;
1983 else
1984 kind = LDF_VOLUMES;
1986 port = entry->dol_Task;
1988 for(i = 0 ; i < 100 ; i++)
1990 dl = AttemptLockDosList(LDF_WRITE|kind);
1991 if(((IPTR)dl) <= 1)
1992 dl = NULL;
1994 if(dl != NULL)
1996 RemDosEntry(entry);
1998 UnLockDosList(LDF_WRITE|kind);
2000 result = TRUE;
2002 break;
2005 while((mn = GetMsg(port)) != NULL)
2006 ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
2008 Delay(TICKS_PER_SECOND / 10);
2011 return(result);
2014 /****************************************************************************/
2016 /* Release all resources allocated by the Setup() routine. */
2017 STATIC VOID
2018 Cleanup(VOID)
2020 BOOL send_disk_change = FALSE;
2022 ENTER();
2024 /* If any errors have cropped up, display them now before
2025 * call it quits.
2027 DisplayErrorList();
2029 if(NewProgramName != NULL)
2031 FreeVec(NewProgramName);
2032 NewProgramName = NULL;
2035 if(Parameters != NULL)
2037 FreeArgs(Parameters);
2038 Parameters = NULL;
2041 if(Icon != NULL)
2043 FreeDiskObject(Icon);
2044 Icon = NULL;
2047 if(ServerData != NULL)
2049 smba_disconnect(ServerData);
2050 ServerData = NULL;
2053 if(DeviceNode != NULL)
2055 if(DeviceNodeAdded)
2057 if(ReallyRemoveDosEntry(DeviceNode))
2058 FreeDosEntry(DeviceNode);
2060 else
2062 FreeDosEntry(DeviceNode);
2065 DeviceNode = NULL;
2068 if(VolumeNode != NULL)
2070 if(VolumeNodeAdded)
2072 if(ReallyRemoveDosEntry(VolumeNode))
2073 FreeDosEntry(VolumeNode);
2075 send_disk_change = TRUE;
2077 else
2079 FreeDosEntry(VolumeNode);
2082 VolumeNode = NULL;
2085 if(FileSystemPort != NULL)
2087 struct Message * mn;
2089 /* Return all queued packets; there should be none, though. */
2090 while((mn = GetMsg(FileSystemPort)) != NULL)
2091 ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
2093 DeleteMsgPort(FileSystemPort);
2094 FileSystemPort = NULL;
2097 if(WBStartup == NULL && send_disk_change)
2098 SendDiskChange(IECLASS_DISKREMOVED);
2100 #if defined(__amigaos4__)
2102 if(ITimer != NULL)
2104 DropInterface((struct Interface *)ITimer);
2105 ITimer = NULL;
2108 #endif /* __amigaos4__ */
2110 if(TimerBase != NULL)
2112 CloseDevice((struct IORequest *)&TimerRequest);
2113 TimerBase = NULL;
2116 #if defined(__amigaos4__)
2118 if(ISocket != NULL)
2120 DropInterface((struct Interface *)ISocket);
2121 ISocket = NULL;
2124 #endif /* __amigaos4__ */
2126 if(SocketBase != NULL)
2128 CloseLibrary(SocketBase);
2129 SocketBase = NULL;
2132 #if defined(__amigaos4__)
2134 if(IUtility != NULL)
2136 DropInterface((struct Interface *)IUtility);
2137 IUtility = NULL;
2140 #endif /* __amigaos4__ */
2142 if(UtilityBase != NULL)
2144 CloseLibrary(UtilityBase);
2145 UtilityBase = NULL;
2148 #if defined(__amigaos4__)
2150 if(IIcon != NULL)
2152 DropInterface((struct Interface *)IIcon);
2153 IIcon = NULL;
2156 #endif /* __amigaos4__ */
2158 if(IconBase != NULL)
2160 CloseLibrary(IconBase);
2161 IconBase = NULL;
2164 if(Locale != NULL)
2166 CloseLocale(Locale);
2167 Locale = NULL;
2170 #if defined(__amigaos4__)
2172 if(ILocale != NULL)
2174 DropInterface((struct Interface *)ILocale);
2175 ILocale = NULL;
2178 #endif /* __amigaos4__ */
2180 if(LocaleBase != NULL)
2182 CloseLibrary(LocaleBase);
2183 LocaleBase = NULL;
2186 if(MemoryPool != NULL)
2188 DeletePool(MemoryPool);
2189 MemoryPool = NULL;
2192 #if defined(__amigaos4__)
2194 if(IDOS != NULL)
2196 DropInterface((struct Interface *)IDOS);
2197 IDOS = NULL;
2200 #endif /* __amigaos4__ */
2202 if(DOSBase != NULL)
2204 CloseLibrary(DOSBase);
2205 DOSBase = NULL;
2208 if(WBStartup != NULL)
2210 Forbid();
2211 ReplyMsg((struct Message *)WBStartup);
2214 LEAVE();
2217 /* Allocate all the necessary resources to get going. */
2218 STATIC BOOL
2219 Setup(
2220 STRPTR program_name,
2221 STRPTR service,
2222 STRPTR workgroup,
2223 STRPTR username,
2224 STRPTR opt_password,
2225 BOOL opt_changecase,
2226 STRPTR opt_clientname,
2227 STRPTR opt_servername,
2228 int opt_cachesize,
2229 LONG * opt_time_zone_offset,
2230 LONG * opt_dst_offset,
2231 STRPTR device_name,
2232 STRPTR volume_name,
2233 STRPTR translation_file)
2235 BOOL result = FALSE;
2236 struct DosList * dl;
2237 int error;
2238 STRPTR actual_volume_name;
2239 LONG actual_volume_name_len;
2240 UBYTE name[MAX_FILENAME_LEN];
2241 BOOL device_exists = FALSE;
2242 LONG len,i;
2244 ENTER();
2246 NewList((struct List *)&FileList);
2247 NewList((struct List *)&LockList);
2249 MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC,4096,4096);
2250 if(MemoryPool == NULL)
2252 ReportError("Could not create memory pool.");
2253 goto out;
2256 LocaleBase = OpenLibrary("locale.library",38);
2258 #if defined(__amigaos4__)
2260 if(LocaleBase != NULL)
2262 ILocale = (struct LocaleIFace *)GetInterface(LocaleBase, "main", 1, 0);
2263 if(ILocale == NULL)
2265 CloseLibrary(LocaleBase);
2266 LocaleBase = NULL;
2270 #endif /* __amigaos4__ */
2272 if(LocaleBase != NULL)
2273 Locale = OpenLocale(NULL);
2275 if(opt_time_zone_offset != NULL)
2277 TimeZoneOffset = (*opt_time_zone_offset);
2278 OverrideLocaleTimeZone = TRUE;
2281 if(opt_dst_offset != NULL)
2282 DSTOffset = -60 * (*opt_dst_offset);
2284 memset(&TimerRequest,0,sizeof(TimerRequest));
2286 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest,0) != OK)
2288 ReportError("Could not open 'timer.device'.");
2289 goto out;
2292 TimerBase = (struct Library *)TimerRequest.tr_node.io_Device;
2294 #if defined(__amigaos4__)
2296 if(TimerBase != NULL)
2298 ITimer = (struct TimerIFace *)GetInterface(TimerBase, "main", 1, 0);
2299 if(ITimer == NULL)
2301 ReportError("Could not open 'timer.device'.");
2302 goto out;
2306 #endif /* __amigaos4__ */
2308 SocketBase = OpenLibrary("bsdsocket.library",3);
2310 #if defined(__amigaos4__)
2312 if(SocketBase != NULL)
2314 ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, 0);
2315 if(ISocket == NULL)
2317 CloseLibrary(SocketBase);
2318 SocketBase = NULL;
2322 #endif /* __amigaos4__ */
2324 if(SocketBase == NULL)
2326 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
2327 goto out;
2330 error = SocketBaseTags(
2331 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), &errno,
2332 SBTM_SETVAL(SBTC_HERRNOLONGPTR), &h_errno,
2333 SBTM_SETVAL(SBTC_LOGTAGPTR), program_name,
2334 SBTM_SETVAL(SBTC_BREAKMASK), SIGBREAKF_CTRL_C,
2335 TAG_END);
2336 if(error != OK)
2338 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
2339 goto out;
2342 if(opt_changecase)
2344 for(i = 0 ; i < (LONG)strlen(opt_password) ; i++)
2345 opt_password[i] = ToUpper(opt_password[i]);
2348 TranslateNames = FALSE;
2350 /* Read the translation file, if possible. */
2351 if(translation_file != NULL)
2353 STRPTR msg = NULL;
2354 BPTR file;
2356 error = OK;
2358 file = Open(translation_file,MODE_OLDFILE);
2359 if(file != ZERO)
2361 if(Read(file,A2M,256) != 256 ||
2362 Read(file,M2A,256) != 256)
2364 msg = "Could not read translation file";
2365 error = IoErr();
2368 Close(file);
2370 else
2372 msg = "Could not open translation file";
2373 error = IoErr();
2376 if(msg == NULL)
2378 TranslateNames = TRUE;
2380 else
2382 UBYTE description[100];
2384 Fault(error,NULL,description,sizeof(description));
2385 for(i = ((int)strlen(description)) - 1 ; i >= 0 ; i--)
2387 if(description[i] == '\n')
2388 description[i] = '\0';
2391 ReportError("%s '%s' (%ld, %s).",msg,translation_file,error,description);
2392 goto out;
2396 error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,&ServerData);
2397 if(error < 0)
2398 goto out;
2400 FileSystemPort = CreateMsgPort();
2401 if(FileSystemPort == NULL)
2403 ReportError("Could not create filesystem port.");
2404 goto out;
2407 /* If a device name was provided, check whether it is
2408 * well-formed.
2410 if(device_name != NULL)
2412 len = strlen(device_name);
2413 if(len > 255)
2414 len = 255;
2416 for(i = 0 ; i < len ; i++)
2418 if(device_name[i] == '/')
2420 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
2421 goto out;
2425 /* Lose any trailing colon characters. */
2426 for(i = len-1 ; i >= 0 ; i--)
2428 if(device_name[i] == ':')
2429 len = i;
2432 if(len == 0)
2434 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
2435 goto out;
2438 memcpy(name,device_name,len);
2439 name[len] = '\0';
2441 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2443 if(FindDosEntry(dl,name,LDF_DEVICES) != NULL)
2444 device_exists = TRUE;
2446 else
2448 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2450 /* Find a unique device name. */
2451 for(i = 0 ; i < 100 ; i++)
2453 SPrintf(name,"SMBFS%ld",i);
2455 device_exists = (BOOL)(FindDosEntry(dl,name,LDF_DEVICES) != NULL);
2456 if(NOT device_exists)
2458 device_name = name;
2459 break;
2464 if(device_exists)
2466 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2468 ReportError("Device name '%s:' is already taken.",device_name);
2469 goto out;
2472 /* Finally, create the device node. */
2473 DeviceNode = MakeDosEntry(name,DLT_DEVICE);
2474 if(DeviceNode == NULL)
2476 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2478 ReportError("Could not create device node.");
2479 goto out;
2482 DeviceNode->dol_Task = FileSystemPort;
2484 /* Examine the volume name; make sure that it is
2485 * well-formed.
2487 if(volume_name == NULL)
2488 actual_volume_name = device_name;
2489 else
2490 actual_volume_name = volume_name;
2492 actual_volume_name_len = strlen(actual_volume_name);
2493 if(actual_volume_name_len > 255)
2494 actual_volume_name_len = 255;
2496 for(i = 0 ; i < actual_volume_name_len ; i++)
2498 if(actual_volume_name[i] == '/')
2500 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2502 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2503 goto out;
2507 /* Lose any trailing colon characters. */
2508 for(i = actual_volume_name_len-1 ; i >= 0 ; i--)
2510 if(actual_volume_name[i] == ':')
2511 actual_volume_name_len = i;
2514 if(actual_volume_name_len == 0)
2516 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2518 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2519 goto out;
2522 /* Now, finally, take care of the volume name. */
2523 memcpy(name,actual_volume_name,actual_volume_name_len);
2524 name[actual_volume_name_len] = '\0';
2526 VolumeNode = MakeDosEntry(name,DLT_VOLUME);
2527 if(VolumeNode == NULL)
2529 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2531 ReportError("Could not create volume node.");
2532 goto out;
2535 VolumeNode->dol_Task = FileSystemPort;
2536 DateStamp(&VolumeNode->dol_misc.dol_volume.dol_VolumeDate);
2537 VolumeNode->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
2539 if(DeviceNode != NULL)
2541 AddDosEntry(DeviceNode);
2543 DeviceNodeAdded = TRUE;
2546 /* Note: we always need the volume node to make some file
2547 * system operations safe (e.g. Lock()), but we may
2548 * not always need to make it visible.
2550 if(volume_name != NULL && VolumeNode != NULL)
2552 AddDosEntry(VolumeNode);
2554 VolumeNodeAdded = TRUE;
2557 /* And that concludes the mounting operation. */
2558 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2560 /* Tell Workbench and friends to update their volume lists. */
2561 if(VolumeNodeAdded)
2562 SendDiskChange(IECLASS_DISKINSERTED);
2564 SetProgramName(NewProgramName);
2566 result = TRUE;
2568 out:
2570 RETURN(result);
2571 return(result);
2574 /****************************************************************************/
2577 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2578 #if !defined(__AROS__)
2579 INLINE STATIC VOID
2580 ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
2582 STRPTR from = bstring;
2583 LONG len = from[0];
2585 if(len > max_len-1)
2586 len = max_len-1;
2588 if(len > 0)
2589 memcpy(cstring,from+1,len);
2591 cstring[len] = '\0';
2593 #else
2594 INLINE STATIC VOID
2595 ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
2597 UWORD _i = 0;
2598 UWORD _len = AROS_BSTR_strlen(bstring);
2600 while((_i < _len) && (_i < max_len))
2602 cstring[_i] = AROS_BSTR_getchar(bstring, _i);
2603 _i++;
2606 cstring[_i] = '\0';
2608 #endif
2610 /* Convert a NUL terminated 'C' string into a BCPL string. */
2611 #if !defined(__AROS__)
2612 INLINE STATIC VOID
2613 ConvertCString(LONG max_len, APTR bstring, STRPTR cstring)
2615 LONG len = strlen(cstring);
2616 STRPTR to = bstring;
2618 if(len > max_len-1)
2619 len = max_len-1;
2621 (*to++) = len;
2622 memcpy(to,cstring,len);
2624 #else
2625 INLINE STATIC VOID
2626 ConvertCString(LONG max_len, APTR bstring, STRPTR cstring)
2628 UWORD _i = 0;
2629 while((cstring[_i] != '\0') && (_i < max_len))
2631 AROS_BSTR_putchar(bstring, _i, cstring[_i]);
2632 _i++;
2634 AROS_BSTR_setstrlen(bstring, _i);
2636 #endif
2638 /****************************************************************************/
2640 /* Build the fully qualified name of a file or directory in reference
2641 * to the name of the parent directory. This takes care of all the
2642 * special cases, such as the root directory. The result will be converted
2643 * to be in a form suitable for use with the SMB file sharing service.
2645 STATIC LONG
2646 BuildFullName(
2647 STRPTR parent_name,
2648 STRPTR name,
2649 STRPTR * result_ptr,
2650 LONG * result_size_ptr)
2652 LONG error = OK;
2653 STRPTR buffer;
2654 LONG len,size;
2655 LONG i;
2657 ENTER();
2659 SHOWSTRING(parent_name);
2660 SHOWSTRING(name);
2662 (*result_ptr) = NULL;
2664 /* Throw everything left of the colon away. */
2665 if(name != NULL)
2667 for(i = 0 ; i < (LONG)strlen(name) ; i++)
2669 if(name[i] == ':')
2671 name = &name[i+1];
2672 break;
2677 /* Now, how much room is needed for the complete
2678 * path to fit into a buffer?
2680 len = 2;
2682 if(parent_name != NULL)
2683 len += strlen(parent_name) + 1;
2685 if(name != NULL)
2686 len += strlen(name) + 1;
2688 if(len < SMB_MAXNAMELEN)
2689 len = SMB_MAXNAMELEN;
2691 size = len + 3;
2693 buffer = AllocateMemory(size);
2694 if(buffer == NULL)
2696 error = ERROR_NO_FREE_STORE;
2697 goto out;
2700 /* Start by filling in the path name. */
2701 if(parent_name != NULL)
2703 /* Skip any excess separators. */
2704 while((*parent_name) == SMB_PATH_SEPARATOR)
2705 parent_name++;
2707 buffer[0] = SMB_PATH_SEPARATOR;
2708 strcpy(&buffer[1],parent_name);
2710 else
2712 strcpy(buffer,SMB_ROOT_DIR_NAME);
2715 /* If there's a name to add, do just that. */
2716 if(name != NULL)
2718 LONG segment_start;
2719 LONG segment_len;
2720 LONG buffer_len;
2721 LONG name_len;
2723 buffer_len = strlen(buffer);
2724 name_len = strlen(name);
2726 segment_start = 0;
2728 while(TRUE)
2730 segment_len = 0;
2732 /* Extract the next path name segment. */
2733 for(i = segment_start ; i <= name_len ; i++)
2735 if(i == name_len)
2737 segment_len = i - segment_start;
2738 break;
2740 else if (name[i] == '/')
2742 segment_len = i - segment_start + 1;
2743 break;
2747 /* We're finished if there are no further
2748 * path name segments to take care of.
2750 if(segment_len == 0)
2752 buffer[buffer_len] = '\0';
2753 break;
2756 /* A single slash indicates that we need to move up
2757 * to the parent directory, if any.
2759 if(segment_len == 1 && name[segment_start] == '/')
2761 /* Is this already the root directory name? */
2762 if(buffer_len <= 1)
2764 FreeMemory(buffer);
2765 buffer = NULL;
2767 goto out;
2769 else
2771 /* Skip the last path component. */
2772 for(i = 1 ; i <= buffer_len ; i++)
2774 if(i == buffer_len)
2776 /* We just skipped the first path
2777 * component following the root
2778 * directory name. We preserve
2779 * the first character since it
2780 * refers to the root directory.
2782 buffer_len = 1;
2783 break;
2785 else if (buffer[buffer_len-i] == SMB_PATH_SEPARATOR)
2787 /* This removes both the path separator and
2788 * the name following it.
2790 buffer_len -= i;
2791 break;
2796 else
2798 /* Add a proper separator character if
2799 * necessary.
2801 if(buffer_len > 0 && buffer[buffer_len-1] != SMB_PATH_SEPARATOR)
2802 buffer[buffer_len++] = SMB_PATH_SEPARATOR;
2804 /* Find out how many characters are in that name; this
2805 * excludes the terminating slash.
2807 if(name[segment_start + segment_len - 1] == '/')
2808 len = segment_len - 1;
2809 else
2810 len = segment_len;
2812 memcpy(&buffer[buffer_len],&name[segment_start],len);
2813 buffer_len += len;
2816 segment_start += segment_len;
2820 (*result_ptr) = buffer;
2821 (*result_size_ptr) = size;
2823 SHOWSTRING(buffer);
2825 out:
2827 if(error != OK)
2828 FreeMemory(buffer);
2830 RETURN(error);
2831 return(error);
2834 /****************************************************************************/
2836 STATIC BPTR
2837 Action_Parent(
2838 struct FileLock * parent,
2839 SIPTR * error_ptr)
2841 BPTR result = ZERO;
2842 STRPTR full_name = NULL;
2843 LONG full_name_size;
2844 STRPTR parent_name;
2845 BOOL cleanup = TRUE;
2846 struct LockNode * ln = NULL;
2847 LONG error;
2849 ENTER();
2851 SHOWVALUE(parent);
2853 if(parent != NULL)
2855 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2857 parent_name = parent_ln->ln_FullName;
2859 else
2861 parent_name = NULL;
2864 error = BuildFullName(parent_name,"/",&full_name,&full_name_size);
2865 if(error != OK)
2866 goto out;
2868 /* Check if we ended up having to return the parent of
2869 * the root directory. This is indicated by a NULL
2870 * name pointer and a zero error code.
2872 if(full_name == NULL)
2873 goto out;
2875 ln = AllocateMemory(sizeof(*ln));
2876 if(ln == NULL)
2878 error = ERROR_NO_FREE_STORE;
2879 goto out;
2882 memset(ln,0,sizeof(*ln));
2884 ln->ln_FileLock.fl_Key = (IPTR)ln;
2885 ln->ln_FileLock.fl_Access = SHARED_LOCK;
2886 ln->ln_FileLock.fl_Task = FileSystemPort;
2887 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
2888 ln->ln_FullName = full_name;
2890 SHOWSTRING(full_name);
2892 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2893 if(error < 0)
2895 error = MapErrnoToIoErr(error);
2896 goto out;
2899 AddTail((struct List *)&LockList,(struct Node *)ln);
2900 result = MKBADDR(&ln->ln_FileLock);
2901 cleanup = FALSE;
2902 SHOWVALUE(&ln->ln_FileLock);
2904 out:
2906 if(cleanup)
2908 FreeMemory(full_name);
2909 FreeMemory(ln);
2912 (*error_ptr) = error;
2914 RETURN(result);
2915 return(result);
2918 /****************************************************************************/
2920 /* Find the lock node corresponding to a given name,
2921 * starting from node start. (if node, this one is skipped)
2923 STATIC struct LockNode *
2924 FindNextLockNode(STRPTR name,struct LockNode * last_ln)
2926 struct LockNode * result = NULL;
2927 struct LockNode * ln;
2928 struct LockNode * start;
2930 if(last_ln != NULL)
2931 start = (struct LockNode *)last_ln->ln_MinNode.mln_Succ;
2932 else
2933 start = (struct LockNode *)LockList.mlh_Head;
2935 for(ln = start ;
2936 ln->ln_MinNode.mln_Succ != NULL ;
2937 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
2939 if(CompareNames(name,ln->ln_FullName) == SAME)
2941 result = ln;
2942 break;
2946 return(result);
2949 /****************************************************************************/
2951 STATIC LONG
2952 Action_DeleteObject(
2953 struct FileLock * parent,
2954 APTR bcpl_name,
2955 SIPTR * error_ptr)
2957 LONG result = DOSFALSE;
2958 STRPTR full_name = NULL;
2959 LONG full_name_size;
2960 smba_file_t * file = NULL;
2961 STRPTR parent_name;
2962 STRPTR full_parent_name = NULL;
2963 UBYTE name[MAX_FILENAME_LEN];
2964 struct LockNode * ln;
2965 smba_stat_t st;
2966 LONG error;
2968 ENTER();
2970 if(WriteProtected)
2972 error = ERROR_DISK_WRITE_PROTECTED;
2973 goto out;
2976 SHOWVALUE(parent);
2978 if(parent != NULL)
2980 ln = (struct LockNode *)parent->fl_Key;
2982 parent_name = ln->ln_FullName;
2984 else
2986 parent_name = NULL;
2989 ConvertBString(sizeof(name),name,bcpl_name);
2990 TranslateCName(name,A2M);
2992 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2993 if(error != OK)
2994 goto out;
2996 /* Trying to delete the root directory, are you kidding? */
2997 if(full_name == NULL)
2999 error = ERROR_OBJECT_WRONG_TYPE;
3000 goto out;
3003 /* We need to find this file's parent directory, so that
3004 * in case the directory contents are currently being
3005 * examined, that process is restarted.
3007 full_parent_name = AllocateMemory(strlen(full_name)+3);
3008 if(full_parent_name == NULL)
3010 error = ERROR_NO_FREE_STORE;
3011 goto out;
3014 strcpy(full_parent_name,full_name);
3016 /* Build the parent object name - Piru */
3017 if (full_parent_name[0] != '\0')
3019 int i;
3021 i = strlen(full_parent_name) - 1;
3022 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
3023 i--;
3025 for ( ; i >= 0 ; i--)
3027 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
3029 full_parent_name[i] = '\0';
3030 break;
3035 /* NOTE: Mark all locks to this object as restart, not just first
3036 one - Piru */
3037 ln = NULL;
3038 while ((ln = FindNextLockNode(full_parent_name, ln)) != NULL)
3039 ln->ln_RestartExamine = TRUE;
3041 ln = FindLockNode(full_parent_name,NULL);
3042 if(ln != NULL)
3043 ln->ln_RestartExamine = TRUE;
3045 FreeMemory(full_parent_name);
3046 full_parent_name = NULL;
3048 SHOWSTRING(full_name);
3050 error = smba_open(ServerData,full_name,full_name_size,&file);
3051 if(error < 0)
3053 error = MapErrnoToIoErr(error);
3054 goto out;
3057 error = smba_getattr(file,&st);
3058 if(error < 0)
3060 error = MapErrnoToIoErr(error);
3061 goto out;
3064 smba_close(file);
3065 file = NULL;
3067 if(st.is_dir)
3069 SHOWMSG("removing a directory");
3071 error = smba_rmdir(ServerData,full_name);
3072 if(error < 0)
3074 SHOWVALUE(error);
3076 /* This is a little bit difficult to justify since
3077 * the error code may indicate a different cause,
3078 * but in practice 'EACCES' seems to be returned
3079 * if the directory to remove is not empty.
3081 if(error == (-EACCES))
3082 error = ERROR_DIRECTORY_NOT_EMPTY;
3083 else
3084 error = MapErrnoToIoErr(error);
3086 goto out;
3089 else
3091 SHOWMSG("removing a file");
3093 error = smba_remove(ServerData,full_name);
3094 if(error < 0)
3096 SHOWVALUE(error);
3098 error = MapErrnoToIoErr(error);
3099 goto out;
3103 SHOWMSG("done.");
3105 result = DOSTRUE;
3107 out:
3109 FreeMemory(full_name);
3110 FreeMemory(full_parent_name);
3111 if(file != NULL)
3112 smba_close(file);
3114 (*error_ptr) = error;
3116 RETURN(result);
3117 return(result);
3120 /****************************************************************************/
3122 STATIC BPTR
3123 Action_CreateDir(
3124 struct FileLock * parent,
3125 APTR bcpl_name,
3126 SIPTR * error_ptr)
3128 BPTR result = ZERO;
3129 STRPTR full_name = NULL;
3130 LONG full_name_size;
3131 struct LockNode * ln = NULL;
3132 STRPTR parent_name;
3133 STRPTR dir_name = NULL;
3134 smba_file_t * dir = NULL;
3135 STRPTR base_name;
3136 UBYTE name[MAX_FILENAME_LEN];
3137 LONG error;
3138 LONG i;
3140 ENTER();
3142 if(WriteProtected)
3144 error = ERROR_DISK_WRITE_PROTECTED;
3145 goto out;
3148 SHOWVALUE(parent);
3150 if(parent != NULL)
3152 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
3154 parent_name = parent_ln->ln_FullName;
3156 else
3158 parent_name = NULL;
3161 ConvertBString(sizeof(name),name,bcpl_name);
3162 TranslateCName(name,A2M);
3164 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3165 if(error != OK)
3166 goto out;
3168 /* Trying to overwrite the root directory, are you kidding? */
3169 if(full_name == NULL)
3171 error = ERROR_OBJECT_IN_USE;
3172 goto out;
3175 dir_name = AllocateMemory(strlen(full_name)+3);
3176 if(dir_name == NULL)
3178 error = ERROR_NO_FREE_STORE;
3179 goto out;
3182 strcpy(dir_name,full_name);
3183 base_name = NULL;
3184 for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
3186 if(dir_name[i] == SMB_PATH_SEPARATOR)
3188 if(i == 0)
3190 memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1);
3191 i++;
3194 dir_name[i] = '\0';
3196 base_name = &dir_name[i+1];
3197 break;
3201 ln = AllocateMemory(sizeof(*ln));
3202 if(ln == NULL)
3204 error = ERROR_NO_FREE_STORE;
3205 goto out;
3208 memset(ln,0,sizeof(*ln));
3210 ln->ln_FileLock.fl_Key = (IPTR)ln;
3211 ln->ln_FileLock.fl_Access = EXCLUSIVE_LOCK;
3212 ln->ln_FileLock.fl_Task = FileSystemPort;
3213 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3214 ln->ln_FullName = full_name;
3216 error = smba_open(ServerData,dir_name,strlen(full_name)+3,&dir);
3217 if(error < 0)
3219 error = MapErrnoToIoErr(error);
3220 goto out;
3223 error = smba_mkdir(dir,base_name);
3224 if(error < 0)
3226 error = MapErrnoToIoErr(error);
3227 goto out;
3230 smba_close(dir);
3231 dir = NULL;
3233 SHOWSTRING(full_name);
3235 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3236 if(error < 0)
3238 error = MapErrnoToIoErr(error);
3239 goto out;
3242 AddTail((struct List *)&LockList,(struct Node *)ln);
3243 result = MKBADDR(&ln->ln_FileLock);
3244 SHOWVALUE(&ln->ln_FileLock);
3246 out:
3248 if(dir != NULL)
3249 smba_close(dir);
3251 FreeMemory(dir_name);
3253 if(result == ZERO)
3255 FreeMemory(full_name);
3256 FreeMemory(ln);
3259 (*error_ptr) = error;
3261 RETURN(result);
3262 return(result);
3265 /****************************************************************************/
3267 STATIC BPTR
3268 Action_LocateObject(
3269 struct FileLock * parent,
3270 APTR bcpl_name,
3271 LONG mode,
3272 SIPTR * error_ptr)
3274 BPTR result = ZERO;
3275 STRPTR full_name = NULL;
3276 LONG full_name_size;
3277 struct LockNode * ln = NULL;
3278 STRPTR parent_name;
3279 UBYTE name[MAX_FILENAME_LEN];
3280 LONG error;
3282 ENTER();
3284 SHOWVALUE(parent);
3286 if(parent != NULL)
3288 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
3290 parent_name = parent_ln->ln_FullName;
3292 else
3294 parent_name = NULL;
3297 ConvertBString(sizeof(name),name,bcpl_name);
3298 TranslateCName(name,A2M);
3300 if(IsReservedName(FilePart(name)))
3302 error = ERROR_OBJECT_NOT_FOUND;
3303 goto out;
3306 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3307 if(error != OK)
3308 goto out;
3310 /* Trying to get a lock on the root directory's parent?
3311 * My pleasure.
3313 if(full_name == NULL)
3314 goto out;
3316 ln = AllocateMemory(sizeof(*ln));
3317 if(ln == NULL)
3319 error = ERROR_NO_FREE_STORE;
3320 goto out;
3323 memset(ln,0,sizeof(*ln));
3325 ln->ln_FileLock.fl_Key = (IPTR)ln;
3326 ln->ln_FileLock.fl_Access = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK;
3327 ln->ln_FileLock.fl_Task = FileSystemPort;
3328 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3329 ln->ln_FullName = full_name;
3331 error = CheckAccessModeCollision(full_name,ln->ln_FileLock.fl_Access);
3332 if(error != OK)
3333 goto out;
3335 SHOWSTRING(full_name);
3337 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3338 if(error < 0)
3340 error = MapErrnoToIoErr(error);
3341 goto out;
3344 AddTail((struct List *)&LockList,(struct Node *)ln);
3345 result = MKBADDR(&ln->ln_FileLock);
3346 SHOWVALUE(&ln->ln_FileLock);
3348 out:
3350 if(result == ZERO)
3352 FreeMemory(full_name);
3353 FreeMemory(ln);
3356 (*error_ptr) = error;
3358 RETURN(result);
3359 return(result);
3362 /****************************************************************************/
3364 STATIC BPTR
3365 Action_CopyDir(
3366 struct FileLock * lock,
3367 SIPTR * error_ptr)
3369 BPTR result = ZERO;
3370 STRPTR full_name = NULL;
3371 LONG full_name_size;
3372 struct LockNode * ln = NULL;
3373 STRPTR source_name;
3374 LONG source_mode;
3375 LONG error;
3377 ENTER();
3379 SHOWVALUE(lock);
3381 if(lock != NULL && lock->fl_Access != SHARED_LOCK)
3383 SHOWMSG("cannot duplicate exclusive lock");
3384 error = ERROR_OBJECT_IN_USE;
3385 goto out;
3388 ln = AllocateMemory(sizeof(*ln));
3389 if(ln == NULL)
3391 error = ERROR_NO_FREE_STORE;
3392 goto out;
3395 memset(ln,0,sizeof(*ln));
3397 if(lock != NULL)
3399 struct LockNode * source = (struct LockNode *)lock->fl_Key;
3401 source_name = source->ln_FullName;
3402 source_mode = source->ln_FileLock.fl_Access;
3404 else
3406 source_name = SMB_ROOT_DIR_NAME;
3407 source_mode = SHARED_LOCK;
3410 full_name_size = strlen(source_name)+3;
3411 if(full_name_size < SMB_MAXNAMELEN+1)
3412 full_name_size = SMB_MAXNAMELEN+1;
3414 full_name = AllocateMemory(full_name_size);
3415 if(full_name == NULL)
3417 error = ERROR_NO_FREE_STORE;
3418 goto out;
3421 strcpy(full_name,source_name);
3423 ln->ln_FileLock.fl_Key = (IPTR)ln;
3424 ln->ln_FileLock.fl_Access = source_mode;
3425 ln->ln_FileLock.fl_Task = FileSystemPort;
3426 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3427 ln->ln_FullName = full_name;
3429 SHOWSTRING(full_name);
3431 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3432 if(error < 0)
3434 error = MapErrnoToIoErr(error);
3435 goto out;
3438 AddTail((struct List *)&LockList,(struct Node *)ln);
3439 result = MKBADDR(&ln->ln_FileLock);
3440 SHOWVALUE(&ln->ln_FileLock);
3442 out:
3444 if(result == ZERO)
3446 FreeMemory(full_name);
3447 FreeMemory(ln);
3450 (*error_ptr) = error;
3452 RETURN(result);
3453 return(result);
3456 /****************************************************************************/
3458 STATIC LONG
3459 Action_FreeLock(
3460 struct FileLock * lock,
3461 SIPTR * error_ptr)
3463 LONG result = DOSTRUE;
3464 struct LockNode * ln;
3465 LONG error = OK;
3467 ENTER();
3469 SHOWVALUE(lock);
3471 if(lock == NULL)
3472 goto out;
3474 ln = (struct LockNode *)lock->fl_Key;
3476 Remove((struct Node *)ln);
3477 smba_close(ln->ln_File);
3478 FreeMemory(ln->ln_FullName);
3479 FreeMemory(ln);
3481 out:
3483 (*error_ptr) = error;
3485 RETURN(result);
3486 return(result);
3489 /****************************************************************************/
3491 STATIC LONG
3492 Action_SameLock(
3493 struct FileLock * lock1,
3494 struct FileLock * lock2,
3495 SIPTR * error_ptr)
3497 LONG result = DOSFALSE;
3498 STRPTR name1;
3499 STRPTR name2;
3500 LONG error = OK;
3502 ENTER();
3504 SHOWVALUE(lock1);
3505 SHOWVALUE(lock2);
3507 if(lock1 != NULL)
3509 struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
3511 name1 = ln->ln_FullName;
3513 else
3515 name1 = SMB_ROOT_DIR_NAME;
3518 if(lock2 != NULL)
3520 struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
3522 name2 = ln->ln_FullName;
3524 else
3526 name2 = SMB_ROOT_DIR_NAME;
3529 SHOWSTRING(name1);
3530 SHOWSTRING(name2);
3532 if(Stricmp(name1,name2) == SAME)
3533 result = DOSTRUE;
3535 (*error_ptr) = error;
3537 RETURN(result);
3538 return(result);
3541 /****************************************************************************/
3543 STATIC LONG
3544 Action_SetProtect(
3545 struct FileLock * parent,
3546 APTR bcpl_name,
3547 LONG mask,
3548 SIPTR * error_ptr)
3550 LONG result = DOSFALSE;
3551 STRPTR full_name = NULL;
3552 LONG full_name_size;
3553 smba_file_t * file = NULL;
3554 STRPTR parent_name;
3555 UBYTE name[MAX_FILENAME_LEN];
3556 smba_stat_t st;
3557 LONG error;
3559 ENTER();
3561 if(WriteProtected)
3563 error = ERROR_DISK_WRITE_PROTECTED;
3564 goto out;
3567 SHOWVALUE(parent);
3569 if(parent != NULL)
3571 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
3573 parent_name = ln->ln_FullName;
3575 else
3577 parent_name = NULL;
3580 ConvertBString(sizeof(name),name,bcpl_name);
3581 TranslateCName(name,A2M);
3583 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3584 if(error != OK)
3585 goto out;
3587 /* Trying to change the protection bits of the root
3588 * directory, are you kidding?
3590 if(full_name == NULL)
3592 error = ERROR_OBJECT_WRONG_TYPE;
3593 goto out;
3596 SHOWSTRING(full_name);
3598 error = smba_open(ServerData,full_name,full_name_size,&file);
3599 if(error < 0)
3601 error = MapErrnoToIoErr(error);
3602 goto out;
3605 memset(&st,0,sizeof(st));
3607 mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
3609 st.atime = -1;
3610 st.ctime = -1;
3611 st.mtime = -1;
3612 st.size = -1;
3614 if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
3616 SHOWMSG("write protection enabled");
3617 st.is_wp = TRUE;
3619 else
3621 SHOWMSG("write protection disabled");
3624 /* Careful: the 'archive' attribute has exactly the opposite
3625 * meaning in the Amiga and the SMB worlds.
3627 st.is_archive = ((mask & FIBF_ARCHIVE) == 0);
3629 /* The 'system' attribute is associated with the 'pure' bit for now. */
3630 st.is_system = ((mask & FIBF_PURE) != 0);
3632 error = smba_setattr(file,&st);
3633 if(error < 0)
3635 error = MapErrnoToIoErr(error);
3636 goto out;
3639 result = DOSTRUE;
3641 out:
3643 FreeMemory(full_name);
3644 if(file != NULL)
3645 smba_close(file);
3647 (*error_ptr) = error;
3649 RETURN(result);
3650 return(result);
3653 /****************************************************************************/
3655 STATIC LONG
3656 Action_RenameObject(
3657 struct FileLock * source_lock,
3658 APTR source_bcpl_name,
3659 struct FileLock * destination_lock,
3660 APTR destination_bcpl_name,
3661 SIPTR * error_ptr)
3663 struct LockNode * ln;
3664 LONG result = DOSFALSE;
3665 STRPTR full_source_name = NULL;
3666 LONG full_source_name_size;
3667 STRPTR full_destination_name = NULL;
3668 LONG full_destination_name_size;
3669 UBYTE name[MAX_FILENAME_LEN];
3670 STRPTR parent_name;
3671 LONG error;
3673 ENTER();
3675 if(WriteProtected)
3677 error = ERROR_DISK_WRITE_PROTECTED;
3678 goto out;
3681 SHOWVALUE(source_lock);
3682 SHOWVALUE(destination_lock);
3684 if(source_lock != NULL)
3686 ln = (struct LockNode *)source_lock->fl_Key;
3688 parent_name = ln->ln_FullName;
3690 else
3692 parent_name = NULL;
3695 ConvertBString(sizeof(name),name,source_bcpl_name);
3696 TranslateCName(name,A2M);
3698 error = BuildFullName(parent_name,name,&full_source_name,&full_source_name_size);
3699 if(error != OK)
3700 goto out;
3702 /* Trying to rename the root directory, are you kidding? */
3703 if(full_source_name == NULL)
3705 error = ERROR_OBJECT_IN_USE;
3706 goto out;
3709 if(destination_lock != NULL)
3711 ln = (struct LockNode *)destination_lock->fl_Key;
3713 parent_name = ln->ln_FullName;
3715 else
3717 parent_name = NULL;
3720 ConvertBString(sizeof(name),name,destination_bcpl_name);
3721 TranslateCName(name,A2M);
3723 error = BuildFullName(parent_name,name,&full_destination_name,&full_destination_name_size);
3724 if(error != OK)
3725 goto out;
3727 /* Trying to rename the root directory, are you kidding? */
3728 if(full_destination_name == NULL)
3730 error = ERROR_OBJECT_IN_USE;
3731 goto out;
3734 error = NameAlreadyInUse(full_source_name);
3735 if(error != OK)
3736 goto out;
3738 error = NameAlreadyInUse(full_destination_name);
3739 if(error != OK)
3740 goto out;
3742 SHOWSTRING(full_source_name);
3743 SHOWSTRING(full_destination_name);
3745 error = smba_rename(ServerData,full_source_name,full_destination_name);
3746 if(error < 0)
3748 error = MapErrnoToIoErr(error);
3749 goto out;
3752 result = DOSTRUE;
3754 out:
3756 FreeMemory(full_source_name);
3757 FreeMemory(full_destination_name);
3759 (*error_ptr) = error;
3761 RETURN(result);
3762 return(result);
3765 /****************************************************************************/
3767 STATIC LONG
3768 Action_DiskInfo(
3769 struct InfoData * id,
3770 SIPTR * error_ptr)
3772 LONG result = DOSTRUE;
3773 long block_size;
3774 long num_blocks;
3775 long num_blocks_free;
3776 LONG error;
3778 ENTER();
3780 memset(id,0,sizeof(*id));
3782 if(WriteProtected)
3783 id->id_DiskState = ID_WRITE_PROTECTED;
3784 else
3785 id->id_DiskState = ID_VALIDATED;
3787 error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
3788 if(error >= 0)
3790 SHOWMSG("got the disk data");
3791 SHOWVALUE(block_size);
3792 SHOWVALUE(num_blocks);
3793 SHOWVALUE(num_blocks_free);
3795 if(block_size <= 0)
3796 block_size = 512;
3798 if(block_size < 512)
3800 num_blocks /= (512 / block_size);
3801 num_blocks_free /= (512 / block_size);
3803 else if (block_size > 512)
3805 num_blocks *= (block_size / 512);
3806 num_blocks_free *= (block_size / 512);
3809 id->id_NumBlocks = num_blocks;
3810 id->id_NumBlocksUsed = num_blocks - num_blocks_free;
3811 id->id_BytesPerBlock = 512;
3812 id->id_DiskType = ID_DOS_DISK;
3813 id->id_VolumeNode = MKBADDR(VolumeNode);
3814 id->id_InUse = NOT (IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList));
3816 if(id->id_NumBlocks == 0)
3817 id->id_NumBlocks = 1;
3819 if(id->id_NumBlocksUsed == 0)
3820 id->id_NumBlocksUsed = 1;
3822 else
3824 SHOWMSG("could not get any disk data");
3826 id->id_NumBlocks = 1;
3827 id->id_NumBlocksUsed = 1;
3828 id->id_BytesPerBlock = 512;
3829 id->id_DiskType = ID_NO_DISK_PRESENT;
3831 error = MapErrnoToIoErr(error);
3832 result = DOSFALSE;
3835 SHOWVALUE(id->id_NumBlocks);
3836 SHOWVALUE(id->id_NumBlocksUsed);
3837 SHOWVALUE(id->id_BytesPerBlock);
3838 SHOWVALUE(id->id_DiskType);
3839 SHOWVALUE(id->id_VolumeNode);
3840 SHOWVALUE(id->id_InUse);
3842 (*error_ptr) = error;
3844 RETURN(result);
3845 return(result);
3848 STATIC LONG
3849 Action_Info(
3850 struct FileLock * lock,
3851 struct InfoData * id,
3852 SIPTR * error_ptr)
3854 LONG result;
3856 ENTER();
3858 SHOWVALUE(lock);
3860 if(lock == NULL || lock->fl_Volume != MKBADDR(VolumeNode))
3862 SHOWMSG("volume node does not match");
3864 result = DOSFALSE;
3866 (*error_ptr) = ERROR_NO_DISK;
3868 else
3870 result = Action_DiskInfo(id,error_ptr);
3873 RETURN(result);
3874 return(result);
3877 /****************************************************************************/
3879 STATIC LONG
3880 Action_ExamineObject(
3881 struct FileLock * lock,
3882 struct FileInfoBlock * fib,
3883 SIPTR * error_ptr)
3885 LONG result = DOSFALSE;
3886 LONG error = OK;
3888 ENTER();
3890 SHOWVALUE(lock);
3892 memset(fib,0,sizeof(*fib));
3894 if(lock == NULL)
3896 #if !defined(__AROS__)
3897 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3898 LONG len = volume_name[0];
3900 memcpy(fib->fib_FileName+1, volume_name + 1, len);
3901 fib->fib_FileName[0] = len;
3902 #else
3903 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3904 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3906 memcpy(fib->fib_FileName, volume_name, len);
3907 #endif
3908 SHOWMSG("ZERO root lock");
3910 fib->fib_DirEntryType = ST_ROOT;
3911 fib->fib_EntryType = ST_ROOT;
3912 fib->fib_NumBlocks = 1;
3913 fib->fib_Date = VolumeNode->dol_misc.dol_volume.dol_VolumeDate;
3914 fib->fib_DiskKey = -1;
3915 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3916 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3918 else
3920 struct LockNode * ln = (struct LockNode *)lock->fl_Key;
3921 LONG seconds;
3922 smba_stat_t st;
3924 error = smba_getattr(ln->ln_File,&st);
3925 if(error < 0)
3927 SHOWMSG("information not available");
3929 error = MapErrnoToIoErr(error);
3930 goto out;
3933 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3934 if(seconds < 0)
3935 seconds = 0;
3937 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
3938 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
3939 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
3941 SHOWSTRING(ln->ln_FullName);
3943 if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME)
3945 #if !defined(__AROS__)
3946 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3947 LONG len = volume_name[0];
3949 memcpy(fib->fib_FileName+1, volume_name + 1, len);
3950 fib->fib_FileName[0] = len;
3951 #else
3952 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3953 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3955 memcpy(fib->fib_FileName, volume_name, len);
3956 #endif
3957 SHOWMSG("root lock");
3959 fib->fib_DirEntryType = ST_ROOT;
3960 fib->fib_EntryType = ST_ROOT;
3961 fib->fib_NumBlocks = 1;
3962 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3963 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3965 else
3967 STRPTR name;
3968 LONG i;
3970 name = ln->ln_FullName;
3971 for(i = strlen(name)-1 ; i >= 0 ; i--)
3973 if(name[i] == SMB_PATH_SEPARATOR)
3975 name = &name[i+1];
3976 break;
3980 /* Just checking: will the name fit? */
3981 if(strlen(name) >= sizeof(fib->fib_FileName))
3983 error = ERROR_INVALID_COMPONENT_NAME;
3984 goto out;
3987 ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
3988 TranslateBName(fib->fib_FileName,M2A);
3990 fib->fib_DirEntryType = st.is_dir ? ST_USERDIR : ST_FILE;
3991 fib->fib_EntryType = fib->fib_DirEntryType;
3992 fib->fib_NumBlocks = (st.size + 511) / 512;
3993 fib->fib_Size = st.size;
3994 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3995 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3997 if(st.is_wp)
3998 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4000 /* Careful: the 'archive' attribute has exactly the opposite
4001 * meaning in the Amiga and the SMB worlds.
4003 if(NOT st.is_archive)
4004 fib->fib_Protection |= FIBF_ARCHIVE;
4006 if(st.is_system)
4007 fib->fib_Protection |= FIBF_PURE;
4009 if(NOT st.is_dir)
4010 fib->fib_DiskKey = -1;
4014 result = DOSTRUE;
4016 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib->fib_FileName)));
4017 SHOWVALUE(fib->fib_DirEntryType);
4018 SHOWVALUE(fib->fib_NumBlocks);
4019 SHOWVALUE(fib->fib_Size);
4020 SHOWVALUE(fib->fib_Date.ds_Days);
4021 SHOWVALUE(fib->fib_Date.ds_Minute);
4022 SHOWVALUE(fib->fib_Date.ds_Tick);
4023 SHOWVALUE(fib->fib_DiskKey);
4025 out:
4027 (*error_ptr) = error;
4029 RETURN(result);
4030 return(result);
4033 /****************************************************************************/
4035 STATIC BOOL
4036 NameIsAcceptable(STRPTR name,LONG max_len)
4038 BOOL result = FALSE;
4039 UBYTE c;
4041 /* This takes care of "." and "..". */
4042 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
4043 goto out;
4045 /* Now for embedded '/', ':' and '\' characters and
4046 * names that just don't want to fit.
4048 while((c = (*name++)) != '\0')
4050 max_len--;
4051 if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
4052 goto out;
4055 result = TRUE;
4057 out:
4059 return(result);
4062 /****************************************************************************/
4064 static int
4065 dir_scan_callback_func_exnext(
4066 struct FileInfoBlock * fib,
4067 int unused_fpos,
4068 int nextpos,
4069 char * name,
4070 int eof,
4071 smba_stat_t * st)
4073 int result;
4075 ENTER();
4077 D((" '%s'",name));
4078 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4079 st->is_dir,st->is_wp,st->is_hidden,st->size));
4080 D((" nextpos=%ld eof=%ld",nextpos,eof));
4082 /* Skip file and drawer names that we wouldn't be
4083 * able to handle in the first place.
4085 if(NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) && NOT (st->is_hidden && OmitHidden))
4087 LONG seconds;
4089 ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
4090 TranslateBName(fib->fib_FileName,M2A);
4092 fib->fib_DirEntryType = st->is_dir ? ST_USERDIR : ST_FILE;
4093 fib->fib_EntryType = fib->fib_DirEntryType;
4094 fib->fib_NumBlocks = (st->size + 511) / 512;
4095 fib->fib_Size = st->size;
4096 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
4097 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
4099 if(st->is_wp)
4100 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4102 /* Careful: the 'archive' attribute has exactly the opposite
4103 * meaning in the Amiga and the SMB worlds.
4105 if(NOT st->is_archive)
4106 fib->fib_Protection |= FIBF_ARCHIVE;
4108 if(st->is_system)
4109 fib->fib_Protection |= FIBF_PURE;
4111 seconds = st->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4112 if(seconds < 0)
4113 seconds = 0;
4115 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
4116 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
4117 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
4119 result = 1;
4121 else
4123 result = 0;
4126 fib->fib_DiskKey = eof ? -1 : nextpos;
4128 RETURN(result);
4129 return(result);
4132 STATIC LONG
4133 Action_ExamineNext(
4134 struct FileLock * lock,
4135 struct FileInfoBlock * fib,
4136 SIPTR * error_ptr)
4138 struct LockNode * ln;
4139 LONG result = DOSFALSE;
4140 LONG error = OK;
4141 long offset;
4142 int count;
4144 ENTER();
4146 SHOWVALUE(lock);
4148 if(fib->fib_DiskKey == -1)
4150 SHOWMSG("scanning finished.");
4151 error = ERROR_NO_MORE_ENTRIES;
4152 goto out;
4155 if(lock == NULL)
4157 SHOWMSG("invalid lock");
4158 error = ERROR_INVALID_LOCK;
4159 goto out;
4162 offset = fib->fib_DiskKey;
4164 ln = (struct LockNode *)lock->fl_Key;
4166 /* Check if we should restart scanning the directory
4167 * contents. This is tricky at best and may produce
4168 * irritating results :(
4170 if(ln->ln_RestartExamine)
4172 offset = 0;
4174 ln->ln_RestartExamine = FALSE;
4177 memset(fib,0,sizeof(*fib));
4179 SHOWMSG("calling 'smba_readdir'");
4180 SHOWVALUE(offset);
4182 count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
4184 SHOWVALUE(count);
4186 if(count == 0 || fib->fib_FileName[0] == '\0')
4188 SHOWMSG("nothing to be read");
4189 fib->fib_DiskKey = -1;
4191 error = ERROR_NO_MORE_ENTRIES;
4192 goto out;
4194 else if (count == (-EIO))
4196 SHOWMSG("ouch! directory read error");
4197 fib->fib_DiskKey = -1;
4199 error = ERROR_NO_DEFAULT_DIR;
4200 goto out;
4202 else if (count < 0)
4204 SHOWMSG("error whilst scanning");
4205 SHOWVALUE(count);
4206 fib->fib_DiskKey = -1;
4208 error = MapErrnoToIoErr(count);
4209 goto out;
4212 result = DOSTRUE;
4214 out:
4216 (*error_ptr) = error;
4218 RETURN(result);
4219 return(result);
4222 /****************************************************************************/
4224 struct ExAllContext
4226 struct ExAllData * ec_Last;
4227 struct ExAllData * ec_Next;
4228 ULONG ec_BytesLeft;
4229 ULONG ec_MinSize;
4230 struct ExAllControl * ec_Control;
4231 ULONG ec_Type;
4232 LONG ec_Error;
4233 BOOL ec_FirstAttempt;
4236 static int
4237 dir_scan_callback_func_exall(
4238 struct ExAllContext * ec,
4239 int unused_fpos,
4240 int nextpos,
4241 char * name,
4242 int eof,
4243 smba_stat_t * st)
4245 int result = 0;
4247 ENTER();
4249 D((" '%s'",name));
4250 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4251 st->is_dir,st->is_wp,st->is_hidden,st->size));
4252 D((" nextpos=%ld eof=%ld",nextpos,eof));
4254 /* Skip file and drawer names that we wouldn't be
4255 * able to handle in the first place.
4257 if(NameIsAcceptable((STRPTR)name,MAX_FILENAME_LEN) && NOT (st->is_hidden && OmitHidden))
4259 struct ExAllData * ed;
4260 ULONG size;
4261 ULONG type = ec->ec_Type;
4262 BOOL take_it;
4264 size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3UL;
4265 SHOWVALUE(size);
4266 if(size > ec->ec_BytesLeft)
4268 D(("size %ld > ec->ec_BytesLeft %ld",size,ec->ec_BytesLeft));
4270 /* If this is the first directory entry,
4271 * stop the entire process before it has
4272 * really begun.
4274 if(ec->ec_FirstAttempt)
4276 SHOWMSG("this was the first read attempt.");
4277 ec->ec_Control->eac_Entries = 0;
4278 ec->ec_Error = ERROR_NO_FREE_STORE;
4280 else
4282 SHOWMSG("try again");
4283 ec->ec_Error = 0;
4286 result = 1;
4287 goto out;
4290 ed = ec->ec_Next;
4292 ed->ed_Next = NULL;
4293 ed->ed_Name = (STRPTR)(((IPTR)ed) + ec->ec_MinSize);
4294 strcpy(ed->ed_Name,name);
4296 TranslateCName(ed->ed_Name,M2A);
4298 if(type >= ED_TYPE)
4299 ed->ed_Type = st->is_dir ? ST_USERDIR : ST_FILE;
4301 if(type >= ED_SIZE)
4302 ed->ed_Size = st->size;
4304 if(type >= ED_PROTECTION)
4306 ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
4307 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
4309 if(st->is_wp)
4310 ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4312 /* Careful: the 'archive' attribute has exactly the opposite
4313 * meaning in the Amiga and the SMB worlds.
4315 if(NOT st->is_archive)
4316 ed->ed_Prot |= FIBF_ARCHIVE;
4318 if(st->is_system)
4319 ed->ed_Prot |= FIBF_PURE;
4322 if(type >= ED_DATE)
4324 LONG seconds;
4326 seconds = st->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4327 if(seconds < 0)
4328 seconds = 0;
4330 ed->ed_Days = (seconds / (24 * 60 * 60));
4331 ed->ed_Mins = (seconds % (24 * 60 * 60)) / 60;
4332 ed->ed_Ticks = (seconds % 60) * TICKS_PER_SECOND;
4335 if(type >= ED_COMMENT)
4336 ed->ed_Comment = "";
4338 if(type >= ED_OWNER)
4339 ed->ed_OwnerUID = ed->ed_OwnerGID = 0;
4341 take_it = TRUE;
4343 if(ec->ec_Control->eac_MatchString != NULL)
4345 SHOWMSG("checking against match string");
4346 if(NOT MatchPatternNoCase(ec->ec_Control->eac_MatchString,ed->ed_Name))
4348 SHOWMSG("does not match");
4349 take_it = FALSE;
4353 if(take_it && ec->ec_Control->eac_MatchFunc != NULL)
4355 SHOWMSG("calling match func");
4357 /* NOTE: the order of the parameters passed to the match hook
4358 * function can be somewhat confusing. For standard
4359 * hook functions, the order of the parameters and the
4360 * registers they go into is hook=A0, object=A2,
4361 * message=A1. However, the documentation for the 'ExAll()'
4362 * function always lists them in ascending order, that is
4363 * hook=A0, message=A1, object=A2, which can lead to
4364 * quite some confusion and strange errors.
4366 if(NOT CallHookPkt(ec->ec_Control->eac_MatchFunc,&type,ed))
4368 SHOWMSG("does not match");
4369 take_it = FALSE;
4373 if(take_it)
4375 SHOWMSG("registering new entry");
4377 if(ec->ec_Last != NULL)
4378 ec->ec_Last->ed_Next = ed;
4380 ec->ec_Last = ed;
4381 ec->ec_Next = (struct ExAllData *)(((IPTR)ed) + size);
4382 ec->ec_BytesLeft -= size;
4383 ec->ec_Control->eac_Entries++;
4385 SHOWVALUE(ec->ec_Last->ed_Next);
4386 SHOWVALUE(ed->ed_Name);
4387 SHOWVALUE(ed->ed_Comment);
4391 ec->ec_Control->eac_LastKey = (ULONG)(eof ? -1 : nextpos);
4393 out:
4395 ec->ec_FirstAttempt = FALSE;
4397 RETURN(result);
4398 return(result);
4401 STATIC LONG
4402 Action_ExamineAll(
4403 struct FileLock * lock,
4404 struct ExAllData * ed,
4405 ULONG size,
4406 ULONG type,
4407 struct ExAllControl * eac,
4408 SIPTR * error_ptr)
4410 struct ExAllContext ec;
4411 struct LockNode * ln;
4412 LONG result = DOSFALSE;
4413 LONG error = OK;
4414 LONG offset;
4415 int count;
4417 ENTER();
4419 SHOWVALUE(lock);
4421 SHOWVALUE(eac->eac_LastKey);
4423 eac->eac_Entries = 0;
4425 if(size < sizeof(ed->ed_Next))
4427 SHOWMSG("buffer is far too short.");
4428 error = ERROR_NO_FREE_STORE;
4429 goto out;
4432 ed->ed_Next = NULL;
4434 if(eac->eac_LastKey == (ULONG)-1)
4436 SHOWMSG("scanning finished.");
4437 error = ERROR_NO_MORE_ENTRIES;
4438 goto out;
4441 if(lock == NULL)
4443 SHOWMSG("invalid lock");
4444 error = ERROR_INVALID_LOCK;
4445 goto out;
4448 if(type < ED_NAME || type > ED_OWNER)
4450 D(("type %ld not supported",type));
4451 error = ERROR_BAD_NUMBER;
4452 goto out;
4455 SHOWVALUE(type);
4457 memset(&ec,0,sizeof(ec));
4459 ec.ec_Next = ed;
4460 ec.ec_BytesLeft = size;
4461 ec.ec_Control = eac;
4462 ec.ec_Type = type;
4463 ec.ec_Error = ERROR_NO_MORE_ENTRIES;
4464 ec.ec_FirstAttempt = TRUE;
4466 switch(type)
4468 case ED_NAME:
4470 ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
4471 break;
4473 case ED_TYPE:
4475 ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
4476 break;
4478 case ED_SIZE:
4480 ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
4481 break;
4483 case ED_PROTECTION:
4485 ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
4486 break;
4488 case ED_DATE:
4490 ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
4491 break;
4493 case ED_COMMENT:
4495 ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
4496 break;
4498 case ED_OWNER:
4500 ec.ec_MinSize = sizeof(struct ExAllData);
4501 break;
4504 SHOWVALUE(ec.ec_MinSize);
4506 offset = eac->eac_LastKey;
4508 ln = (struct LockNode *)lock->fl_Key;
4510 /* Check if we should restart scanning the directory
4511 * contents. This is tricky at best and may produce
4512 * irritating results :(
4514 if(ln->ln_RestartExamine)
4516 offset = 0;
4518 ln->ln_RestartExamine = FALSE;
4521 if(offset == 0)
4523 smba_stat_t st;
4525 SHOWMSG("first invocation");
4527 SHOWMSG("getting file attributes");
4528 error = smba_getattr(ln->ln_File,&st);
4529 if(error < 0)
4531 SHOWMSG("didn't work");
4532 error = MapErrnoToIoErr(error);
4533 eac->eac_LastKey = (ULONG)-1;
4534 goto out;
4537 if(NOT st.is_dir)
4539 SHOWMSG("lock does not refer to a directory");
4540 error = ERROR_OBJECT_WRONG_TYPE;
4541 eac->eac_LastKey = (ULONG)-1;
4542 goto out;
4546 SHOWMSG("calling 'smba_readdir'");
4547 SHOWVALUE(offset);
4549 count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
4551 SHOWVALUE(count);
4553 if(count == 0 || eac->eac_Entries == 0)
4555 SHOWMSG("nothing to be read");
4556 if(ec.ec_Error != OK)
4558 SHOWMSG("flagging an error");
4559 SHOWVALUE(ec.ec_Error);
4560 eac->eac_LastKey = (ULONG)-1;
4561 error = ec.ec_Error;
4564 goto out;
4566 else if (count == (-EIO))
4568 SHOWMSG("ouch! directory read error");
4569 eac->eac_LastKey = (ULONG)-1;
4571 error = ERROR_NO_DEFAULT_DIR;
4572 goto out;
4574 else if (count < 0)
4576 SHOWMSG("error whilst scanning");
4577 eac->eac_LastKey = (ULONG)-1;
4579 error = MapErrnoToIoErr(count);
4580 goto out;
4583 SHOWMSG("ok");
4584 result = DOSTRUE;
4586 out:
4588 #if DEBUG
4590 SHOWVALUE(eac->eac_Entries);
4592 while(ed != NULL)
4594 SHOWSTRING(ed->ed_Name);
4596 ed = ed->ed_Next;
4599 #endif /* DEBUG */
4601 (*error_ptr) = error;
4603 RETURN(result);
4604 return(result);
4607 /****************************************************************************/
4609 STATIC LONG
4610 Action_Find(
4611 LONG action,
4612 struct FileHandle * fh,
4613 struct FileLock * parent,
4614 APTR bcpl_name,
4615 SIPTR * error_ptr)
4617 LONG result = DOSFALSE;
4618 STRPTR parent_path = NULL;
4619 STRPTR full_name = NULL;
4620 LONG full_name_size;
4621 struct FileNode * fn = NULL;
4622 STRPTR parent_name;
4623 UBYTE name[MAX_FILENAME_LEN];
4624 BOOL create_new_file;
4625 LONG error;
4627 ENTER();
4629 switch(action)
4631 case ACTION_FINDINPUT:
4632 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
4633 break;
4635 case ACTION_FINDOUTPUT:
4636 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
4637 break;
4639 case ACTION_FINDUPDATE:
4640 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
4641 break;
4644 SHOWVALUE(parent);
4646 if(parent != NULL)
4648 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
4650 parent_name = ln->ln_FullName;
4652 else
4654 parent_name = NULL;
4657 ConvertBString(sizeof(name),name,bcpl_name);
4658 TranslateCName(name,A2M);
4660 if(IsReservedName(FilePart(name)))
4662 error = ERROR_OBJECT_NOT_FOUND;
4663 goto out;
4666 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
4667 if(error != OK)
4668 goto out;
4670 /* Trying to open the root directory? */
4671 if(full_name == NULL)
4673 error = ERROR_OBJECT_WRONG_TYPE;
4674 goto out;
4677 fn = AllocateMemory(sizeof(*fn));
4678 if(fn == NULL)
4680 error = ERROR_NO_FREE_STORE;
4681 goto out;
4684 memset(fn,0,sizeof(*fn));
4686 fn->fn_Handle = fh;
4687 fn->fn_FullName = full_name;
4688 fn->fn_Mode = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK;
4690 error = CheckAccessModeCollision(full_name,fn->fn_Mode);
4691 if(error != OK)
4692 goto out;
4694 SHOWSTRING(full_name);
4696 if(action == ACTION_FINDOUTPUT)
4698 /* Definitely create a new file. */
4699 create_new_file = TRUE;
4701 else if (action == ACTION_FINDINPUT)
4703 /* Open an existing file for reading. */
4704 create_new_file = FALSE;
4706 else if (action == ACTION_FINDUPDATE)
4708 smba_file_t * file = NULL;
4709 smba_stat_t st;
4711 if(smba_open(ServerData,full_name,full_name_size,&file) == OK &&
4712 smba_getattr(file,&st) == OK)
4714 /* File apparently opens Ok and information on it
4715 * is available, don't try to replace it.
4717 create_new_file = FALSE;
4719 else
4721 /* We try to ignore the error here and assume
4722 * that the remainder of the file opening
4723 * procedure will produce a useful error
4724 * report. In the mean time, assume that the
4725 * file needs to be created.
4727 create_new_file = TRUE;
4730 if(file != NULL)
4731 smba_close(file);
4733 else
4735 /* What's that? */
4736 error = ERROR_ACTION_NOT_KNOWN;
4737 goto out;
4740 /* Create a new file? */
4741 if(create_new_file)
4743 smba_stat_t st;
4744 smba_file_t * dir;
4745 STRPTR base_name;
4746 LONG i;
4748 if(WriteProtected)
4750 error = ERROR_DISK_WRITE_PROTECTED;
4751 goto out;
4754 parent_path = AllocateMemory(strlen(full_name)+3);
4755 if(parent_path == NULL)
4757 error = ERROR_NO_FREE_STORE;
4758 goto out;
4761 strcpy(parent_path,full_name);
4762 base_name = NULL;
4763 for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
4765 if(parent_path[i] == SMB_PATH_SEPARATOR)
4767 if(i == 0)
4769 memmove(&parent_path[1],&parent_path[0],strlen(parent_path)+1);
4770 i++;
4773 parent_path[i] = '\0';
4775 base_name = &parent_path[i+1];
4776 break;
4780 SHOWMSG("creating a file; finding parent path first");
4781 SHOWSTRING(parent_path);
4783 error = smba_open(ServerData,parent_path,strlen(full_name)+3,&dir);
4784 if(error < 0)
4786 error = MapErrnoToIoErr(error);
4787 goto out;
4790 /* Only one attribute counts: the file should not be write protected. */
4791 memset(&st,0,sizeof(st));
4793 SHOWMSG("now trying to create the file");
4794 SHOWSTRING(base_name);
4796 error = smba_create(dir,base_name,&st);
4797 if(error < 0)
4799 SHOWMSG("didn't work.");
4800 SHOWVALUE(error);
4802 smba_close(dir);
4803 error = MapErrnoToIoErr(error);
4805 SHOWVALUE(error);
4807 goto out;
4810 SHOWMSG("good.");
4812 smba_close(dir);
4815 /* Now for the remainder... */
4816 error = smba_open(ServerData,full_name,full_name_size,&fn->fn_File);
4817 if(error < 0)
4819 error = MapErrnoToIoErr(error);
4820 goto out;
4823 fh->fh_Arg1 = (IPTR)fn;
4825 AddTail((struct List *)&FileList,(struct Node *)fn);
4826 result = DOSTRUE;
4828 out:
4830 if(result == DOSFALSE)
4832 FreeMemory(full_name);
4833 FreeMemory(fn);
4836 FreeMemory(parent_path);
4838 (*error_ptr) = error;
4840 RETURN(result);
4841 return(result);
4844 /****************************************************************************/
4846 STATIC LONG
4847 Action_Read(
4848 struct FileNode * fn,
4849 APTR mem,
4850 LONG length,
4851 SIPTR * error_ptr)
4853 LONG result = 0;
4854 LONG error = OK;
4856 ENTER();
4858 if(length > 0)
4860 result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
4861 if(result < 0)
4863 error = MapErrnoToIoErr(result);
4864 result = -1;
4865 goto out;
4868 fn->fn_Offset += result;
4871 out:
4873 (*error_ptr) = error;
4875 RETURN(result);
4876 return(result);
4879 /****************************************************************************/
4881 STATIC LONG
4882 Action_Write(
4883 struct FileNode * fn,
4884 APTR mem,
4885 LONG length,
4886 SIPTR * error_ptr)
4888 LONG result = DOSFALSE;
4889 LONG error = OK;
4891 ENTER();
4893 if(WriteProtected)
4895 error = ERROR_DISK_WRITE_PROTECTED;
4896 goto out;
4899 if(length > 0)
4901 result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
4902 if(result < 0)
4904 error = MapErrnoToIoErr(result);
4905 result = -1;
4906 goto out;
4909 fn->fn_Offset += result;
4912 out:
4914 (*error_ptr) = error;
4916 RETURN(result);
4917 return(result);
4920 /****************************************************************************/
4922 STATIC LONG
4923 Action_End(
4924 struct FileNode * fn,
4925 SIPTR * error_ptr)
4927 Remove((struct Node *)fn);
4929 smba_close(fn->fn_File);
4930 FreeMemory(fn->fn_FullName);
4931 FreeMemory(fn);
4933 (*error_ptr) = OK;
4934 return(DOSTRUE);
4937 /****************************************************************************/
4939 STATIC LONG
4940 Action_Seek(
4941 struct FileNode * fn,
4942 LONG position,
4943 LONG mode,
4944 SIPTR * error_ptr)
4946 LONG previous_position = fn->fn_Offset;
4947 LONG result = -1;
4948 LONG offset;
4949 LONG error;
4951 ENTER();
4953 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4954 #if 0
4956 switch(mode)
4958 case OFFSET_BEGINNING:
4960 mode = 0;
4961 break;
4963 case OFFSET_CURRENT:
4965 mode = 1;
4966 break;
4968 case OFFSET_END:
4970 mode = 2;
4971 break;
4973 default:
4975 error = ERROR_ACTION_NOT_KNOWN;
4976 goto out;
4979 error = smba_seek (fn->fn_File, position, mode, (off_t *) &offset);
4980 if(error < 0)
4982 error = MapErrnoToIoErr(error);
4983 goto out;
4986 #endif
4988 /* olsen: This is the original implementation. */
4989 #if 0
4991 smba_stat_t st;
4993 error = smba_getattr(fn->fn_File,&st);
4994 if(error < 0)
4996 error = MapErrnoToIoErr(error);
4997 goto out;
5000 offset = fn->fn_Offset;
5002 switch(mode)
5004 case OFFSET_BEGINNING:
5006 offset = position;
5007 break;
5009 case OFFSET_CURRENT:
5011 offset += position;
5012 break;
5014 case OFFSET_END:
5016 offset = st.size + position;
5017 break;
5019 default:
5021 error = ERROR_ACTION_NOT_KNOWN;
5022 goto out;
5025 if(offset < 0 || offset > st.size)
5027 error = ERROR_SEEK_ERROR;
5028 goto out;
5031 #endif
5033 /* olsen: This is a mix of the two above. First we calculate the absolute
5034 * position, then seek to that position. The SMB server is supposed
5035 * to do its housekeeping before the position is changed. I wish this
5036 * worked differently, but it seems we've got the best of both worlds
5037 * here...
5039 #if 1
5041 smba_stat_t st;
5043 switch(mode)
5045 case OFFSET_BEGINNING:
5047 offset = position;
5048 break;
5050 case OFFSET_CURRENT:
5052 offset = fn->fn_Offset + position;
5053 break;
5055 case OFFSET_END:
5057 error = smba_getattr(fn->fn_File,&st);
5058 if(error < 0)
5060 error = MapErrnoToIoErr(error);
5061 goto out;
5064 offset = st.size + position;
5065 break;
5067 default:
5069 error = ERROR_ACTION_NOT_KNOWN;
5070 goto out;
5073 if(offset < 0)
5075 error = ERROR_SEEK_ERROR;
5076 goto out;
5079 error = smba_seek (fn->fn_File, offset, 0, (off_t *) &offset);
5080 if(error < 0)
5082 error = MapErrnoToIoErr(error);
5083 goto out;
5086 #endif
5088 error = OK;
5090 fn->fn_Offset = offset;
5092 result = previous_position;
5094 out:
5096 (*error_ptr) = error;
5098 RETURN(result);
5099 return(result);
5102 /****************************************************************************/
5104 STATIC LONG
5105 Action_SetFileSize(
5106 struct FileNode * fn,
5107 LONG position,
5108 LONG mode,
5109 SIPTR * error_ptr)
5111 smba_stat_t st;
5112 LONG result = -1;
5113 LONG error;
5114 long offset;
5116 ENTER();
5118 if(WriteProtected)
5120 error = ERROR_DISK_WRITE_PROTECTED;
5121 goto out;
5124 error = smba_getattr(fn->fn_File,&st);
5125 if(error < 0)
5127 error = MapErrnoToIoErr(error);
5128 goto out;
5131 offset = fn->fn_Offset;
5133 switch(mode)
5135 case OFFSET_BEGINNING:
5137 offset = position;
5138 break;
5140 case OFFSET_CURRENT:
5142 offset += position;
5143 break;
5145 case OFFSET_END:
5147 offset = st.size + position;
5148 break;
5150 default:
5152 error = ERROR_ACTION_NOT_KNOWN;
5153 goto out;
5156 if(offset < 0)
5158 error = ERROR_SEEK_ERROR;
5159 goto out;
5162 st.atime = -1;
5163 st.ctime = -1;
5164 st.mtime = -1;
5165 st.size = offset;
5167 error = smba_setattr(fn->fn_File,&st);
5168 if(error < 0)
5170 error = MapErrnoToIoErr(error);
5171 goto out;
5174 if(fn->fn_Offset > offset)
5175 fn->fn_Offset = offset;
5177 result = offset;
5179 out:
5181 (*error_ptr) = error;
5183 RETURN(result);
5184 return(result);
5187 /****************************************************************************/
5189 STATIC LONG
5190 Action_SetDate(
5191 struct FileLock * parent,
5192 APTR bcpl_name,
5193 struct DateStamp * ds,
5194 SIPTR * error_ptr)
5196 LONG result = DOSFALSE;
5197 STRPTR full_name = NULL;
5198 LONG full_name_size;
5199 smba_file_t * file = NULL;
5200 STRPTR parent_name;
5201 UBYTE name[MAX_FILENAME_LEN];
5202 smba_stat_t st;
5203 LONG seconds;
5204 LONG error;
5206 ENTER();
5208 if(WriteProtected)
5210 error = ERROR_DISK_WRITE_PROTECTED;
5211 goto out;
5214 SHOWVALUE(parent);
5216 if(parent != NULL)
5218 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5220 parent_name = ln->ln_FullName;
5222 else
5224 parent_name = NULL;
5227 ConvertBString(sizeof(name),name,bcpl_name);
5228 TranslateCName(name,A2M);
5230 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5231 if(error != OK)
5232 goto out;
5234 /* Trying to change the date of the root directory? */
5235 if(full_name == NULL)
5237 error = ERROR_OBJECT_IN_USE;
5238 goto out;
5241 SHOWSTRING(full_name);
5243 error = smba_open(ServerData,full_name,full_name_size,&file);
5244 if(error < 0)
5246 error = MapErrnoToIoErr(error);
5247 goto out;
5250 error = smba_getattr(file,&st);
5251 if(error < 0)
5253 error = MapErrnoToIoErr(error);
5254 goto out;
5257 seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
5259 st.atime = -1;
5260 st.ctime = -1;
5261 st.mtime = seconds + UNIX_TIME_OFFSET + GetTimeZoneDelta();
5262 st.size = -1;
5264 error = smba_setattr(file,&st);
5265 if(error < 0)
5267 error = MapErrnoToIoErr(error);
5268 goto out;
5271 result = DOSTRUE;
5273 out:
5275 FreeMemory(full_name);
5276 if(file != NULL)
5277 smba_close(file);
5279 (*error_ptr) = error;
5281 RETURN(result);
5282 return(result);
5285 /****************************************************************************/
5287 STATIC LONG
5288 Action_ExamineFH(
5289 struct FileNode * fn,
5290 struct FileInfoBlock * fib,
5291 SIPTR * error_ptr)
5293 LONG result = DOSFALSE;
5294 smba_stat_t st;
5295 LONG error;
5296 LONG seconds;
5297 STRPTR name;
5298 LONG i;
5300 ENTER();
5302 error = smba_getattr(fn->fn_File,&st);
5303 if(error < 0)
5305 error = MapErrnoToIoErr(error);
5306 goto out;
5309 name = fn->fn_FullName;
5310 for(i = strlen(name)-1 ; i >= 0 ; i--)
5312 if(name[i] == SMB_PATH_SEPARATOR)
5314 name = &name[i+1];
5315 break;
5319 /* Just checking: will the name fit? */
5320 if(strlen(name) >= sizeof(fib->fib_FileName))
5322 error = ERROR_INVALID_COMPONENT_NAME;
5323 goto out;
5326 memset(fib,0,sizeof(*fib));
5328 ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
5329 TranslateBName(fib->fib_FileName,M2A);
5331 fib->fib_DirEntryType = ST_FILE;
5332 fib->fib_EntryType = ST_FILE;
5333 fib->fib_NumBlocks = (st.size + 511) / 512;
5334 fib->fib_Size = st.size;
5335 fib->fib_DiskKey = -1;
5337 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
5338 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
5340 if(st.is_wp)
5341 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
5343 /* Careful: the 'archive' attribute has exactly the opposite
5344 * meaning in the Amiga and the SMB worlds.
5346 if(NOT st.is_archive)
5347 fib->fib_Protection |= FIBF_ARCHIVE;
5349 if(st.is_system)
5350 fib->fib_Protection |= FIBF_PURE;
5352 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
5353 if(seconds < 0)
5354 seconds = 0;
5356 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
5357 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
5358 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
5360 result = DOSTRUE;
5362 out:
5364 (*error_ptr) = error;
5366 RETURN(result);
5367 return(result);
5370 /****************************************************************************/
5372 STATIC BPTR
5373 Action_ParentFH(
5374 struct FileNode * fn,
5375 SIPTR * error_ptr)
5377 BPTR result = ZERO;
5378 struct LockNode * ln = NULL;
5379 LONG error;
5380 STRPTR full_name;
5381 LONG full_name_size;
5382 LONG i;
5384 ENTER();
5386 full_name_size = strlen(fn->fn_FullName)+3;
5387 if(full_name_size < SMB_MAXNAMELEN+1)
5388 full_name_size = SMB_MAXNAMELEN+1;
5390 full_name = AllocateMemory(full_name_size);
5391 if(full_name == NULL)
5393 error = ERROR_NO_FREE_STORE;
5394 goto out;
5397 strcpy(full_name,fn->fn_FullName);
5399 for(i = strlen(full_name)-1 ; i >= 0 ; i--)
5401 if(i == 0)
5403 strcpy(full_name,SMB_ROOT_DIR_NAME);
5404 break;
5406 else if (full_name[i] == SMB_PATH_SEPARATOR)
5408 full_name[i] = '\0';
5409 break;
5413 ln = AllocateMemory(sizeof(*ln));
5414 if(ln == NULL)
5416 error = ERROR_NO_FREE_STORE;
5417 goto out;
5420 memset(ln,0,sizeof(*ln));
5422 ln->ln_FileLock.fl_Key = (IPTR)ln;
5423 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5424 ln->ln_FileLock.fl_Task = FileSystemPort;
5425 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5426 ln->ln_FullName = full_name;
5428 SHOWSTRING(full_name);
5430 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5431 if(error < 0)
5433 error = MapErrnoToIoErr(error);
5434 goto out;
5437 AddTail((struct List *)&LockList,(struct Node *)ln);
5438 result = MKBADDR(&ln->ln_FileLock);
5439 SHOWVALUE(&ln->ln_FileLock);
5441 out:
5443 if(result == ZERO)
5445 FreeMemory(ln);
5446 FreeMemory(full_name);
5449 (*error_ptr) = error;
5451 RETURN(result);
5452 return(result);
5455 /****************************************************************************/
5457 STATIC BPTR
5458 Action_CopyDirFH(
5459 struct FileNode * fn,
5460 SIPTR * error_ptr)
5462 BPTR result = ZERO;
5463 struct LockNode * ln = NULL;
5464 STRPTR full_name = NULL;
5465 LONG full_name_size;
5466 LONG error;
5468 ENTER();
5470 if(fn->fn_Mode != SHARED_LOCK)
5472 error = ERROR_OBJECT_IN_USE;
5473 goto out;
5476 full_name_size = strlen(fn->fn_FullName)+3;
5477 if(full_name_size < SMB_MAXNAMELEN+1)
5478 full_name_size = SMB_MAXNAMELEN+1;
5480 full_name = AllocateMemory(full_name_size);
5481 if(full_name == NULL)
5483 error = ERROR_NO_FREE_STORE;
5484 goto out;
5487 strcpy(full_name,fn->fn_FullName);
5489 ln = AllocateMemory(sizeof(*ln));
5490 if(ln == NULL)
5492 error = ERROR_NO_FREE_STORE;
5493 goto out;
5496 memset(ln,0,sizeof(*ln));
5498 ln->ln_FileLock.fl_Key = (IPTR)ln;
5499 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5500 ln->ln_FileLock.fl_Task = FileSystemPort;
5501 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5502 ln->ln_FullName = full_name;
5504 SHOWSTRING(full_name);
5506 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5507 if(error < 0)
5509 error = MapErrnoToIoErr(error);
5510 goto out;
5513 AddTail((struct List *)&LockList,(struct Node *)ln);
5514 result = MKBADDR(&ln->ln_FileLock);
5515 SHOWVALUE(&ln->ln_FileLock);
5517 out:
5519 if(result == ZERO)
5521 FreeMemory(ln);
5522 FreeMemory(full_name);
5525 (*error_ptr) = error;
5527 RETURN(result);
5528 return(result);
5531 /****************************************************************************/
5533 STATIC LONG
5534 Action_FHFromLock(
5535 struct FileHandle * fh,
5536 struct FileLock * fl,
5537 SIPTR * error_ptr)
5539 LONG result = DOSFALSE;
5540 struct FileNode * fn;
5541 struct LockNode * ln;
5542 LONG error = OK;
5544 ENTER();
5546 SHOWVALUE(fl);
5548 fn = AllocateMemory(sizeof(*fn));
5549 if(fn == NULL)
5551 error = ERROR_NO_FREE_STORE;
5552 goto out;
5555 memset(fn,0,sizeof(*fn));
5557 ln = (struct LockNode *)fl->fl_Key;
5559 fn->fn_Handle = fh;
5560 fn->fn_FullName = ln->ln_FullName;
5561 fn->fn_File = ln->ln_File;
5562 fn->fn_Mode = fl->fl_Access;
5564 Remove((struct Node *)ln);
5565 FreeMemory(ln);
5567 fh->fh_Arg1 = (IPTR)fn;
5569 AddTail((struct List *)&FileList,(struct Node *)fn);
5570 result = DOSTRUE;
5572 out:
5574 (*error_ptr) = error;
5576 RETURN(result);
5577 return(result);
5580 /****************************************************************************/
5582 STATIC LONG
5583 Action_RenameDisk(
5584 APTR bcpl_name,
5585 SIPTR * error_ptr)
5587 LONG result = DOSFALSE;
5588 LONG error = OK;
5589 STRPTR old_name;
5590 STRPTR new_name;
5591 UBYTE * name;
5592 LONG len;
5594 ENTER();
5596 if(NOT VolumeNodeAdded)
5598 error = ERROR_OBJECT_IN_USE;
5599 goto out;
5602 if(WriteProtected)
5604 error = ERROR_DISK_WRITE_PROTECTED;
5605 goto out;
5608 /* Now for the really interesting part; the new name
5609 * is to be a NUL-terminated BCPL string, and as such
5610 * must be allocated via AllocVec().
5613 name = bcpl_name;
5615 len = name[0];
5617 new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
5618 if(new_name == NULL)
5620 error = ERROR_NO_FREE_STORE;
5621 goto out;
5624 new_name[0] = len;
5625 memcpy(&new_name[1],&name[1],len);
5626 new_name[len+1] = '\0';
5628 Forbid();
5630 old_name = BADDR(VolumeNode->dol_Name);
5631 VolumeNode->dol_Name = MKBADDR(new_name);
5633 Permit();
5635 FreeVec(old_name);
5637 SendDiskChange(IECLASS_DISKINSERTED);
5639 result = DOSTRUE;
5641 out:
5643 (*error_ptr) = error;
5645 RETURN(result);
5646 return(result);
5649 /****************************************************************************/
5651 STATIC LONG
5652 Action_ChangeMode(
5653 LONG type,
5654 APTR object,
5655 LONG new_mode,
5656 SIPTR * error_ptr)
5658 LONG result = DOSFALSE;
5659 struct FileLock * fl = NULL;
5660 struct FileNode * fn = NULL;
5661 struct LockNode * ln = NULL;
5662 STRPTR name;
5663 LONG old_mode;
5664 LONG error = OK;
5666 ENTER();
5668 /* Sanity check; verify parameters */
5669 if((type != CHANGE_LOCK && type != CHANGE_FH) ||
5670 (new_mode != EXCLUSIVE_LOCK && new_mode != SHARED_LOCK))
5672 error = ERROR_ACTION_NOT_KNOWN;
5673 goto out;
5676 /* Now obtain the data structures, name and mode
5677 * associated with the object in question.
5679 if(type == CHANGE_LOCK)
5681 fl = object;
5682 ln = (struct LockNode *)fl->fl_Key;
5683 name = ln->ln_FullName;
5684 old_mode = fl->fl_Access;
5686 else
5688 struct FileHandle * fh = object;
5690 fn = (struct FileNode *)fh->fh_Arg1;
5691 name = fn->fn_FullName;
5692 old_mode = fn->fn_Mode;
5695 /* Do we need to change anything at all? */
5696 if(new_mode == old_mode)
5698 result = DOSTRUE;
5699 goto out;
5702 /* This is the easiest case; change an
5703 * exclusive access mode to a shared
5704 * access mode. Since the original mode
5705 * can be used by one object only,
5706 * we get away by updating the mode
5707 * value.
5709 if(new_mode == SHARED_LOCK)
5711 if(type == CHANGE_LOCK)
5712 fl->fl_Access = new_mode;
5713 else
5714 fn->fn_Mode = new_mode;
5716 result = DOSTRUE;
5717 goto out;
5720 /* Is there another shared access lock
5721 * which refers to the same object?
5723 if(FindLockNode(name,ln) != NULL)
5725 error = ERROR_OBJECT_IN_USE;
5726 goto out;
5729 /* Is there another shared access file
5730 * which refers to the same object?
5732 if(FindFileNode(name,fn) != NULL)
5734 error = ERROR_OBJECT_IN_USE;
5735 goto out;
5738 /* There is just one single reference
5739 * to this object; change the mode
5740 * and quit.
5742 if(type == CHANGE_LOCK)
5743 fl->fl_Access = new_mode;
5744 else
5745 fn->fn_Mode = new_mode;
5747 result = DOSTRUE;
5749 out:
5751 (*error_ptr) = error;
5753 RETURN(result);
5754 return(result);
5757 /****************************************************************************/
5759 STATIC LONG
5760 Action_WriteProtect(
5761 LONG flag,
5762 ULONG key,
5763 SIPTR * error_ptr)
5765 LONG result = DOSFALSE;
5766 LONG error = OK;
5768 ENTER();
5770 if(flag == DOSFALSE)
5772 if(WriteProtected)
5774 if(key != WriteProtectKey)
5776 error = ERROR_INVALID_LOCK;
5777 goto out;
5780 WriteProtected = FALSE;
5782 if(VolumeNodeAdded)
5784 SendDiskChange(IECLASS_DISKREMOVED);
5785 SendDiskChange(IECLASS_DISKINSERTED);
5789 else
5791 if(NOT WriteProtected)
5793 WriteProtected = TRUE;
5794 WriteProtectKey = key;
5796 if(VolumeNodeAdded)
5798 SendDiskChange(IECLASS_DISKREMOVED);
5799 SendDiskChange(IECLASS_DISKINSERTED);
5802 else
5804 error = ERROR_INVALID_LOCK;
5805 goto out;
5809 result = DOSTRUE;
5811 out:
5813 (*error_ptr) = error;
5815 RETURN(result);
5816 return(result);
5819 /****************************************************************************/
5821 STATIC LONG
5822 Action_MoreCache(
5823 LONG buffer_delta,
5824 SIPTR * error_ptr)
5826 LONG result;
5827 int old_size;
5829 ENTER();
5831 old_size = smba_get_dircache_size(ServerData);
5833 result = smba_change_dircache_size(ServerData,old_size + buffer_delta);
5835 if(result == old_size && buffer_delta != 0)
5837 result = DOSFALSE;
5838 (*error_ptr) = ERROR_NO_FREE_STORE;
5841 RETURN(result);
5842 return(result);
5845 /****************************************************************************/
5847 STATIC LONG
5848 Action_SetComment(
5849 struct FileLock * parent,
5850 APTR bcpl_name,
5851 APTR bcpl_comment,
5852 SIPTR * error_ptr)
5854 LONG result = DOSFALSE;
5855 STRPTR full_name = NULL;
5856 LONG full_name_size;
5857 smba_file_t * file = NULL;
5858 STRPTR parent_name;
5859 UBYTE name[MAX_FILENAME_LEN];
5860 UBYTE comment[80];
5861 LONG error;
5863 ENTER();
5865 if(WriteProtected)
5867 error = ERROR_DISK_WRITE_PROTECTED;
5868 goto out;
5871 SHOWVALUE(parent);
5873 if(parent != NULL)
5875 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5877 parent_name = ln->ln_FullName;
5879 else
5881 parent_name = NULL;
5884 ConvertBString(sizeof(name),name,bcpl_name);
5885 TranslateCName(name,A2M);
5887 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5888 if(error != OK)
5889 goto out;
5891 /* Trying to change the comment of the root directory? */
5892 if(full_name == NULL)
5894 error = ERROR_OBJECT_IN_USE;
5895 goto out;
5898 SHOWSTRING(full_name);
5900 error = smba_open(ServerData,full_name,full_name_size,&file);
5901 if(error < 0)
5903 error = MapErrnoToIoErr(error);
5904 goto out;
5907 ConvertBString(sizeof(comment),comment,bcpl_comment);
5909 SHOWSTRING(comment);
5911 /* All this work and we're only doing something very silly... */
5912 if(strlen(comment) > 0)
5914 error = ERROR_COMMENT_TOO_BIG;
5915 goto out;
5918 result = DOSTRUE;
5920 out:
5922 FreeMemory(full_name);
5923 if(file != NULL)
5924 smba_close(file);
5926 (*error_ptr) = error;
5928 RETURN(result);
5929 return(result);
5932 /****************************************************************************/
5934 STATIC LONG
5935 Action_LockRecord (
5936 struct FileNode * fn,
5937 LONG offset,
5938 LONG length,
5939 LONG mode,
5940 ULONG timeout,
5941 SIPTR * error_ptr)
5943 LONG result = DOSFALSE;
5944 LONG error;
5945 LONG umode;
5947 /* Sanity checks... */
5948 if (mode < REC_EXCLUSIVE || mode > REC_SHARED_IMMED)
5950 error = ERROR_ACTION_NOT_KNOWN;
5951 goto out;
5954 /* Invalid offset, size or integer overflow? */
5955 if (offset < 0 || length <= 0 || offset + length < offset)
5957 error = ERROR_LOCK_COLLISION;
5958 goto out;
5961 if ((mode == REC_SHARED) || (mode == REC_SHARED_IMMED))
5962 umode = 1;
5963 else
5964 umode = 0;
5966 if ((mode == REC_SHARED_IMMED) || (mode == REC_EXCLUSIVE_IMMED))
5967 timeout = 0;
5969 if (timeout > 0)
5971 if (timeout > 214748364)
5972 timeout = ~0; /* wait forever */
5973 else
5974 timeout *= 20; /* milliseconds instead of Ticks */
5977 error = smba_lockrec (fn->fn_File, offset, length, umode, 0, (long)timeout);
5978 if(error < 0)
5980 error = MapErrnoToIoErr(error);
5981 goto out;
5984 result = DOSTRUE;
5986 out:
5988 (*error_ptr) = error;
5990 RETURN(result);
5991 return(result);
5994 /****************************************************************************/
5996 STATIC LONG
5997 Action_FreeRecord (
5998 struct FileNode * fn,
5999 LONG offset,
6000 LONG length,
6001 SIPTR * error_ptr)
6003 LONG result = DOSFALSE;
6004 LONG error;
6006 /* Sanity checks... */
6007 if(offset < 0 || length <= 0 || offset + length < offset)
6009 error = ERROR_RECORD_NOT_LOCKED;
6010 goto out;
6013 error = smba_lockrec (fn->fn_File, offset, length, 2, -1, 0);
6014 if (error < 0)
6016 error = MapErrnoToIoErr(error);
6017 goto out;
6020 result = DOSTRUE;
6022 out:
6024 (*error_ptr) = error;
6026 RETURN(result);
6027 return(result);
6030 /****************************************************************************/
6032 STATIC VOID
6033 HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name)
6035 BOOL sign_off = FALSE;
6036 ULONG signals;
6037 BOOL done;
6039 ENTER();
6041 DisplayErrorList();
6043 if(NOT Quiet && WBStartup == NULL)
6045 struct CommandLineInterface * cli;
6047 cli = Cli();
6048 if(NOT cli->cli_Background)
6050 struct Process * this_process;
6051 UBYTE name[MAX_FILENAME_LEN];
6052 LONG max_cli;
6053 LONG which;
6054 LONG i;
6056 this_process = (struct Process *)FindTask(NULL);
6058 Forbid();
6060 which = max_cli = MaxCli();
6062 for(i = 1 ; i <= max_cli ; i++)
6064 if(FindCliProc(i) == this_process)
6066 which = i;
6067 break;
6071 Permit();
6073 if(volume_name == NULL)
6074 strlcpy(name,device_name,sizeof(name));
6075 else
6076 strlcpy(name,volume_name,sizeof(name));
6078 for(i = strlen(name)-1 ; i >= 0 ; i--)
6080 if(name[i] == ':')
6081 name[i] = '\0';
6082 else
6083 break;
6086 LocalPrintf("Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ",
6087 service_name,name,which);
6089 Flush(Output());
6091 sign_off = TRUE;
6095 Quiet = TRUE;
6097 done = FALSE;
6101 signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << FileSystemPort->mp_SigBit));
6103 if(signals & (1UL << FileSystemPort->mp_SigBit))
6105 struct DosPacket * dp;
6106 struct Message * mn;
6107 IPTR res1,res2;
6109 while((mn = GetMsg(FileSystemPort)) != NULL)
6111 dp = (struct DosPacket *)mn->mn_Node.ln_Name;
6113 D(("got packet; sender '%s'",((struct Node *)dp->dp_Port->mp_SigTask)->ln_Name));
6115 res2 = 0;
6117 switch(dp->dp_Action)
6119 case ACTION_DIE:
6121 SHOWMSG("ACTION_DIE");
6122 if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
6124 SHOWMSG("no locks or files pending; quitting");
6126 res1 = DOSTRUE;
6128 else
6130 SHOWMSG("locks or files still pending; cannot quit yet");
6132 res1 = DOSFALSE;
6133 res2 = ERROR_OBJECT_IN_USE;
6136 Quit = TRUE;
6137 break;
6139 case ACTION_CURRENT_VOLUME:
6140 /* (Ignore) -> VolumeNode */
6142 res1 = (IPTR)MKBADDR(VolumeNode);
6143 break;
6145 case ACTION_LOCATE_OBJECT:
6146 /* Lock,Name,Mode -> Lock */
6148 res1 = (IPTR)Action_LocateObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6149 break;
6151 case ACTION_RENAME_DISK:
6152 /* Name -> Bool */
6154 res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
6155 break;
6157 case ACTION_FREE_LOCK:
6158 /* Lock -> Bool */
6160 res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6161 break;
6163 case ACTION_DELETE_OBJECT:
6164 /* Lock,Name -> Bool */
6166 res1 = Action_DeleteObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6167 break;
6169 case ACTION_RENAME_OBJECT:
6170 /* Source lock,source name,destination lock,destination name -> Bool */
6172 res1 = Action_RenameObject((struct FileLock *)BADDR(dp->dp_Arg1),BADDR(dp->dp_Arg2),
6173 (struct FileLock *)BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6175 break;
6177 case ACTION_MORE_CACHE:
6178 /* Buffer delta -> Total number of buffers */
6180 /* NOTE: documentation for this packet type is inconsistent;
6181 * in the 'good old' 1.x days 'res1' was documented as
6182 * the total number of buffers to be returned. In the
6183 * 2.x documentation it is said that 'res1' should
6184 * return the success code, with 'res2' to hold the
6185 * total number of buffers. However, the 'AddBuffers'
6186 * shell command doesn't work that way, and the
6187 * dos.library implementation of 'AddBuffers()' doesn't
6188 * work that way either. The 1.3 'AddBuffers' command
6189 * appears to treat a zero result as failure and a
6190 * non-zero result as success, which suggests that this
6191 * is how the packet is supposed to work, contrary to
6192 * what the official documentation says.
6194 res1 = Action_MoreCache(dp->dp_Arg1,&res2);
6195 break;
6197 case ACTION_COPY_DIR:
6198 /* Lock -> Lock */
6200 res1 = (IPTR)Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6201 break;
6203 case ACTION_SET_PROTECT:
6204 /* (Ignore),Lock,Name,Mask -> Bool */
6206 res1 = Action_SetProtect((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),dp->dp_Arg4,&res2);
6207 break;
6209 case ACTION_CREATE_DIR:
6210 /* Lock,Name -> Lock */
6212 res1 = (IPTR)Action_CreateDir((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6213 break;
6215 case ACTION_EXAMINE_OBJECT:
6216 /* FileLock,FileInfoBlock -> Bool */
6218 res1 = Action_ExamineObject((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6219 break;
6221 case ACTION_EXAMINE_NEXT:
6222 /* FileLock,FileInfoBlock -> Bool */
6224 res1 = Action_ExamineNext((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6225 break;
6227 case ACTION_DISK_INFO:
6228 /* InfoData -> Bool */
6230 Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
6231 res1 = DOSTRUE;
6232 res2 = 0;
6233 break;
6235 case ACTION_INFO:
6236 /* FileLock,InfoData -> Bool */
6238 res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
6239 break;
6241 case ACTION_SET_COMMENT:
6242 /* (Ignore),FileLock,Name,Comment -> Bool */
6244 res1 = Action_SetComment((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6245 break;
6247 case ACTION_PARENT:
6248 /* Lock -> Lock */
6250 res1 = (IPTR)Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6251 break;
6253 case ACTION_INHIBIT:
6255 SHOWMSG("ACTION_INHIBIT");
6256 res1 = DOSTRUE;
6257 break;
6259 case ACTION_SET_DATE:
6260 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
6262 res1 = Action_SetDate((struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),(struct DateStamp *)dp->dp_Arg4,&res2);
6263 break;
6265 case ACTION_SAME_LOCK:
6266 /* Lock,Lock -> Bool */
6268 res1 = Action_SameLock((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6269 break;
6271 case ACTION_READ:
6272 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6274 res1 = Action_Read((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6275 break;
6277 case ACTION_WRITE:
6278 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6280 res1 = Action_Write((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6281 break;
6283 case ACTION_FINDUPDATE:
6284 case ACTION_FINDINPUT:
6285 case ACTION_FINDOUTPUT:
6286 /* FileHandle,FileLock,Name -> Bool */
6288 res1 = Action_Find(dp->dp_Action,(struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),&res2);
6289 break;
6291 case ACTION_END:
6292 /* FileHandle->fh_Arg1 -> Bool */
6294 res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
6295 break;
6297 case ACTION_SEEK:
6298 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6300 res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6301 break;
6303 case ACTION_SET_FILE_SIZE:
6304 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
6306 res1 = Action_SetFileSize((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6307 break;
6309 case ACTION_WRITE_PROTECT:
6310 /* Flag,Key -> Bool */
6312 res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
6313 break;
6315 case ACTION_FH_FROM_LOCK:
6316 /* FileHandle(BPTR),FileLock -> Bool */
6318 res1 = Action_FHFromLock((struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6319 break;
6321 case ACTION_IS_FILESYSTEM:
6323 SHOWMSG("ACTION_IS_FILESYSTEM");
6324 res1 = DOSTRUE;
6325 break;
6327 case ACTION_CHANGE_MODE:
6328 /* Type,Object,Mode -> Bool */
6330 res1 = Action_ChangeMode(dp->dp_Arg1,(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6331 break;
6333 case ACTION_COPY_DIR_FH:
6334 /* FileHandle->fh_Arg1 -> Bool */
6336 res1 = (IPTR)Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
6337 break;
6339 case ACTION_PARENT_FH:
6340 /* FileHandle->fh_Arg1 -> Bool */
6342 res1 = (IPTR)Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
6343 break;
6345 case ACTION_EXAMINE_ALL:
6346 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6348 res1 = Action_ExamineAll((struct FileLock *)BADDR(dp->dp_Arg1),(struct ExAllData *)dp->dp_Arg2,
6349 dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2);
6351 break;
6353 case ACTION_EXAMINE_FH:
6354 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
6356 res1 = Action_ExamineFH((struct FileNode *)dp->dp_Arg1,(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6357 break;
6359 case ACTION_EXAMINE_ALL_END:
6360 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6362 res1 = DOSTRUE;
6363 break;
6365 case ACTION_LOCK_RECORD:
6366 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
6367 res1 = Action_LockRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,dp->dp_Arg4,(ULONG)dp->dp_Arg5,&res2);
6368 break;
6370 case ACTION_FREE_RECORD:
6371 /* FileHandle->fh_Arg1,position,length -> Bool */
6372 res1 = Action_FreeRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6373 break;
6375 default:
6377 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
6379 res1 = DOSFALSE;
6380 res2 = ERROR_ACTION_NOT_KNOWN;
6382 break;
6385 SHOWVALUE(res1);
6386 SHOWVALUE(res2);
6388 ReplyPkt(dp,res1,res2);
6390 D(("\n"));
6394 #if DEBUG
6396 if(signals & SIGBREAKF_CTRL_F)
6398 struct FileNode * fn;
6399 struct LockNode * ln;
6401 D(("list of open files:"));
6403 for(fn = (struct FileNode *)FileList.mlh_Head ;
6404 fn->fn_MinNode.mln_Succ != NULL ;
6405 fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
6407 D((" name='%s'",fn->fn_FullName));
6408 D((" mode=%ld, offset=%ld",fn->fn_Mode,fn->fn_Offset));
6409 D((""));
6412 D(("list of allocated locks:"));
6414 for(ln = (struct LockNode *)LockList.mlh_Head ;
6415 ln->ln_MinNode.mln_Succ != NULL ;
6416 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
6418 D((" name='%s'",ln->ln_FullName));
6419 D((" mode=%ld",ln->ln_FileLock.fl_Access));
6420 D((""));
6424 #endif /* DEBUG */
6426 if(signals & SIGBREAKF_CTRL_C)
6427 Quit = TRUE;
6429 if(Quit)
6431 if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
6433 SHOWMSG("no locks or files pending; quitting");
6434 done = TRUE;
6436 else
6438 SHOWMSG("locks or files still pending; cannot quit yet");
6442 while(NOT done);
6444 if(sign_off)
6445 LocalPrintf("stopped.\n");
6447 LEAVE();
6450 /****************************************************************************/
6453 * Copy src to string dst of size siz. At most siz-1 characters
6454 * will be copied. Always NUL terminates (unless siz == 0).
6455 * Returns strlen(src); if retval >= siz, truncation occurred.
6457 size_t
6458 strlcpy(char *dst, const char *src, size_t siz)
6460 char *d = dst;
6461 const char *s = src;
6462 size_t n = siz;
6463 size_t result;
6465 /* Copy as many bytes as will fit */
6466 if(n != 0 && --n != 0)
6470 if(((*d++) = (*s++)) == '\0')
6471 break;
6473 while(--n != 0);
6476 /* Not enough room in dst, add NUL and traverse rest of src */
6477 if(n == 0)
6479 if(siz != 0)
6480 (*d) = '\0'; /* NUL-terminate dst */
6482 while((*s++) != '\0')
6486 result = s - src - 1; /* count does not include NUL */
6488 return(result);
6492 * Appends src to string dst of size siz (unlike strncat, siz is the
6493 * full size of dst, not space left). At most siz-1 characters
6494 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
6495 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
6496 * If retval >= siz, truncation occurred.
6498 size_t
6499 strlcat(char *dst, const char *src, size_t siz)
6501 char *d = dst;
6502 const char *s = src;
6503 size_t n = siz;
6504 size_t dlen;
6505 size_t result;
6507 /* Find the end of dst and adjust bytes left but don't go past end */
6508 while(n-- != 0 && (*d) != '\0')
6509 d++;
6511 dlen = d - dst;
6512 n = siz - dlen;
6514 if(n == 0)
6516 result = dlen + strlen(s);
6518 else
6520 while((*s) != '\0')
6522 if(n != 1)
6524 (*d++) = (*s);
6525 n--;
6528 s++;
6531 (*d) = '\0';
6533 result = dlen + (s - src); /* count does not include NUL */
6536 return(result);