revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / smbfs / source_code / main.c
blobcb7453f6d02baf15ccaf1a3ff015587a7fc90749
1 /*
2 * $Id$
4 * :ts=4
6 * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
8 * Copyright (C) 2000-2016 by Olaf `Olsen' Barthel <obarthel -at- gmx -dot- net>
9 * Copyright (C) 2011-2014,2016-2019, The AROS Development Team
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * cpr smbfs.debug domain=workgroup user=olsen password=... volume=olsen //felix/olsen
28 * cpr smbfs.debug dumpsmb user=guest volume=amiga //windows7-amiga/Users/Public
29 * copy "amiga:Public/Documents/Amiga Files/Shared/dir/Windows-Export/LP2NRFP.h" ram:
30 * smbfs.debug user=guest volume=sicherung //192.168.1.76/sicherung-smb
33 #include "smbfs.h"
35 /****************************************************************************/
37 #include "smb_abstraction.h"
38 #include "utf-8-iso-8859-1-conversion.h"
39 #include "dump_smb.h"
41 /****************************************************************************/
43 #include <smb/smb.h>
45 /****************************************************************************/
47 /* A quick workaround for the timeval/timerequest->TimeVal/TimeRequest
48 change in the recent OS4 header files. */
49 #if defined(__NEW_TIMEVAL_DEFINITION_USED__)
51 #define timeval TimeVal
52 #define tv_secs Seconds
53 #define tv_micro Microseconds
55 #define timerequest TimeRequest
56 #define tr_node Request
57 #define tr_time Time
59 #endif /* __NEW_TIMEVAL_DEFINITION_USED__ */
61 /****************************************************************************/
63 /* This is for backwards compatibility only. */
64 #if defined(__amigaos4__)
65 #define fib_EntryType fib_Obsolete
66 #endif /* __amigaos4__ */
68 /****************************************************************************/
70 #if !defined(__AROS__)
71 #include "smbfs_rev.h"
72 STRPTR Version = VERSTAG;
73 #else
74 CONST TEXT HandlerName[] = "smb-handler";
75 #endif /* __AROS__ */
78 /****************************************************************************/
80 #define UNIX_TIME_OFFSET 252460800
81 #define MAX_FILENAME_LEN 256
83 /****************************************************************************/
85 #define SMB_ROOT_DIR_NAME "\\"
86 #define SMB_PATH_SEPARATOR '\\'
88 /****************************************************************************/
90 typedef STRPTR KEY;
91 typedef LONG * NUMBER;
92 typedef LONG SWITCH;
94 /****************************************************************************/
96 struct FileNode
98 struct MinNode fn_MinNode;
99 struct FileHandle * fn_Handle;
100 LONG fn_Offset;
101 LONG fn_Mode;
102 smba_file_t * fn_File;
103 STRPTR fn_FullName;
106 struct LockNode
108 struct MinNode ln_MinNode;
109 struct FileLock ln_FileLock;
110 smba_file_t * ln_File;
111 BOOL ln_RestartExamine;
112 UWORD ln_Pad;
113 STRPTR ln_FullName;
116 /****************************************************************************/
118 /* The minimum operating system version we require to work. */
119 #define MINIMUM_OS_VERSION 37 /* Kickstart 2.04 or better */
120 /*#define MINIMUM_OS_VERSION 39*/ /* Kickstart 3.0 or better */
122 /****************************************************************************/
124 /* Careful: the memory pool routines in amiga.lib are available only to
125 * SAS/C and similar compilers (not necessarily to GCC).
127 #if defined(__GNUC__) && (MINIMUM_OS_VERSION < 39)
129 #undef MINIMUM_OS_VERSION
130 #define MINIMUM_OS_VERSION 39
132 #endif /* __GNUC__ */
134 /****************************************************************************/
136 #if (MINIMUM_OS_VERSION < 39)
138 /* These are in amiga.lib */
139 APTR ASM AsmCreatePool(REG(d0,ULONG memFlags),REG(d1,ULONG puddleSize),REG(d2,ULONG threshSize),REG(a6,struct Library * SysBase));
140 VOID ASM AsmDeletePool(REG(a0,APTR poolHeader),REG(a6,struct Library * SysBase));
141 APTR ASM AsmAllocPooled(REG(a0,APTR poolHeader),REG(d0,ULONG memSize),REG(a6,struct Library * SysBase));
142 VOID ASM AsmFreePooled(REG(a0,APTR poolHeader),REG(a1,APTR memory),REG(d0,ULONG memSize),REG(a6,struct Library * SysBase));
144 #define CreatePool(memFlags,puddleSize,threshSize) AsmCreatePool((memFlags),(puddleSize),(threshSize),SysBase)
145 #define DeletePool(poolHeader) AsmDeletePool((poolHeader),SysBase)
146 #define AllocPooled(poolHeader,memSize) AsmAllocPooled((poolHeader),(memSize),SysBase)
147 #define FreePooled(poolHeader,memory,memSize) AsmFreePooled((poolHeader),(memory),(memSize),SysBase)
149 #endif /* MINIMUM_OS_VERSION */
151 /****************************************************************************/
153 /* Forward declarations for local routines. */
154 LONG _start(VOID);
155 LONG VARARGS68K LocalPrintf(STRPTR format, ...);
156 STRPTR amitcp_strerror(int error);
157 STRPTR host_strerror(int error);
158 LONG CompareNames(STRPTR a, STRPTR b);
159 VOID StringToUpper(STRPTR s);
160 VOID FreeMemory(APTR address);
161 APTR AllocateMemory(ULONG size);
162 LONG GetTimeZoneDelta(VOID);
163 ULONG GetCurrentTime(VOID);
164 VOID GMTime(time_t seconds, struct tm *tm);
165 time_t MakeTime(const struct tm *const tm);
166 #ifndef __AROS__
167 VOID VARARGS68K ReportError(STRPTR fmt, ...);
168 VOID VARARGS68K SPrintf(STRPTR buffer, STRPTR formatString, ...);
169 #endif
170 int BroadcastNameQuery(char *name, char *scope, UBYTE *address);
172 /****************************************************************************/
174 INLINE STATIC BOOL ReallyRemoveDosEntry(struct DosList *entry);
175 INLINE STATIC LONG BuildFullName(STRPTR parent_name, STRPTR name, STRPTR *result_ptr, LONG *result_size_ptr);
176 INLINE STATIC VOID TranslateCName(UBYTE *name, UBYTE *map);
177 INLINE STATIC VOID ConvertCString(APTR bstring, LONG max_len, STRPTR cstring, LONG len);
178 STATIC VOID DisplayErrorList(VOID);
179 #if !defined(__AROS__)
180 STATIC VOID AddError(STRPTR fmt, APTR args);
181 STATIC LONG CVSPrintf(STRPTR format_string, APTR args);
182 STATIC VOID VSPrintf(STRPTR buffer, STRPTR formatString, APTR args);
183 #endif
184 STATIC VOID SendDiskChange(ULONG class);
185 STATIC struct FileNode *FindFileNode(STRPTR name, struct FileNode *skip);
186 STATIC struct LockNode *FindLockNode(STRPTR name, struct LockNode *skip);
187 STATIC LONG CheckAccessModeCollision(STRPTR name, LONG mode);
188 STATIC LONG NameAlreadyInUse(STRPTR name);
189 STATIC BOOL IsReservedName(STRPTR name);
190 STATIC LONG MapErrnoToIoErr(int error);
191 STATIC VOID TranslateBName(UBYTE *name, UBYTE *map);
192 STATIC VOID Cleanup(VOID);
193 STATIC BOOL Setup(STRPTR opt_password, BOOL opt_changecase, LONG *opt_time_zone_offset, LONG *opt_dst_offset, STRPTR translation_file);
194 STATIC BOOL AddVolume(STRPTR device_name, STRPTR volume_name, STRPTR service, STRPTR workgroup, STRPTR username, STRPTR opt_password, STRPTR opt_clientname, STRPTR opt_servername, int opt_cachesize, int opt_max_transmit, BOOL opt_raw_smb);
195 STATIC VOID ConvertBString(LONG max_len, STRPTR cstring, APTR bstring);
196 STATIC BOOL Action_Startup(struct FileSysStartupMsg *fssm, struct DosList *device_node, SIPTR *error_ptr);
197 STATIC BPTR Action_Parent(struct FileLock *parent, SIPTR *error_ptr);
198 STATIC LONG Action_DeleteObject(struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
199 STATIC BPTR Action_CreateDir(struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
200 STATIC BPTR Action_LocateObject(struct FileLock *parent, APTR bcpl_name, LONG mode, SIPTR *error_ptr);
201 STATIC BPTR Action_CopyDir(struct FileLock *lock, SIPTR *error_ptr);
202 STATIC LONG Action_FreeLock(struct FileLock *lock, SIPTR *error_ptr);
203 STATIC LONG Action_SameLock(struct FileLock *lock1, struct FileLock *lock2, SIPTR *error_ptr);
204 STATIC LONG Action_SetProtect(struct FileLock *parent, APTR bcpl_name, LONG mask, SIPTR *error_ptr);
205 STATIC LONG Action_RenameObject(struct FileLock *source_lock, APTR source_bcpl_name, struct FileLock *destination_lock, APTR destination_bcpl_name, SIPTR *error_ptr);
206 STATIC LONG Action_DiskInfo(struct InfoData *id, SIPTR *error_ptr);
207 STATIC LONG Action_Info(struct FileLock *lock, struct InfoData *id, SIPTR *error_ptr);
208 STATIC LONG Action_ExamineObject(struct FileLock *lock, struct FileInfoBlock *fib, SIPTR *error_ptr);
209 STATIC BOOL NameIsAcceptable(STRPTR name, LONG max_len);
210 STATIC LONG Action_ExamineNext(struct FileLock *lock, struct FileInfoBlock *fib, SIPTR *error_ptr);
211 STATIC LONG Action_ExamineAll(struct FileLock *lock, struct ExAllData *ed, ULONG size, ULONG type, struct ExAllControl *eac, SIPTR *error_ptr);
212 STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, APTR bcpl_name, SIPTR *error_ptr);
213 STATIC LONG Action_Read(struct FileNode *fn, APTR mem, LONG length, SIPTR *error_ptr);
214 STATIC LONG Action_Write(struct FileNode *fn, APTR mem, LONG length, SIPTR *error_ptr);
215 STATIC LONG Action_End(struct FileNode *fn, SIPTR *error_ptr);
216 STATIC LONG Action_Seek(struct FileNode *fn, LONG position, LONG mode, SIPTR *error_ptr);
217 STATIC LONG Action_SetFileSize(struct FileNode *fn, LONG position, LONG mode, SIPTR *error_ptr);
218 STATIC LONG Action_SetDate(struct FileLock *parent, APTR bcpl_name, struct DateStamp *ds, SIPTR *error_ptr);
219 STATIC LONG Action_ExamineFH(struct FileNode *fn, struct FileInfoBlock *fib, SIPTR *error_ptr);
220 STATIC BPTR Action_ParentFH(struct FileNode *fn, SIPTR *error_ptr);
221 STATIC BPTR Action_CopyDirFH(struct FileNode *fn, SIPTR *error_ptr);
222 STATIC LONG Action_FHFromLock(struct FileHandle *fh, struct FileLock *fl, SIPTR *error_ptr);
223 STATIC LONG Action_RenameDisk(APTR bcpl_name, SIPTR *error_ptr);
224 STATIC LONG Action_ChangeMode(LONG type, APTR object, LONG new_mode, SIPTR *error_ptr);
225 STATIC LONG Action_WriteProtect(LONG flag, ULONG key, SIPTR *error_ptr);
226 STATIC LONG Action_MoreCache(LONG buffer_delta, SIPTR *error_ptr);
227 STATIC LONG Action_SetComment(struct FileLock *parent, APTR bcpl_name, APTR bcpl_comment, SIPTR *error_ptr);
228 STATIC LONG Action_LockRecord(struct FileNode *fn, LONG offset, LONG length, LONG mode, ULONG timeout, SIPTR *error_ptr);
229 STATIC LONG Action_FreeRecord(struct FileNode *fn, LONG offset, LONG length, SIPTR *error_ptr);
230 STATIC VOID HandleFileSystem(VOID);
232 /****************************************************************************/
234 #if !defined(__AROS__)
235 struct Library * SysBase;
236 #endif
237 struct Library * DOSBase;
238 struct Library * UtilityBase;
239 struct Library * IntuitionBase;
240 struct Library * SocketBase;
241 struct Library * LocaleBase;
242 struct Library * TimerBase;
243 struct Library * IconBase;
245 /****************************************************************************/
247 #if defined(__amigaos4__)
249 /****************************************************************************/
251 struct ExecIFace * IExec;
252 struct DOSIFace * IDOS;
253 struct UtilityIFace * IUtility;
254 struct IntuitionIFace * IIntuition;
255 struct SocketIFace * ISocket;
256 struct LocaleIFace * ILocale;
257 struct TimerIFace * ITimer;
258 struct IconIFace * IIcon;
260 /****************************************************************************/
262 #endif /* __amigaos4__ */
264 /****************************************************************************/
266 struct timerequest TimerRequest;
268 /****************************************************************************/
270 struct Locale * Locale;
272 /****************************************************************************/
274 #if !defined(__AROS__)
275 int errno;
276 #endif
277 #ifndef h_errno
278 int h_errno;
279 #endif
281 /****************************************************************************/
283 STATIC struct DosList * DeviceNode;
284 STATIC BOOL DeviceNodeAdded;
285 STATIC struct DosList * VolumeNode;
286 STATIC BOOL VolumeNodeAdded;
287 STATIC struct MsgPort * FileSystemPort;
289 STATIC smba_server_t * ServerData;
291 STATIC BOOL Quit;
292 STATIC BOOL Quiet;
293 STATIC BOOL CaseSensitive;
294 STATIC BOOL OmitHidden;
295 STATIC BOOL TranslateUTF8;
297 STATIC LONG DSTOffset;
298 STATIC LONG TimeZoneOffset;
299 STATIC BOOL OverrideLocaleTimeZone;
301 STATIC BOOL WriteProtected;
302 STATIC ULONG WriteProtectKey;
304 STATIC struct MinList FileList;
305 STATIC struct MinList LockList;
307 STATIC APTR MemoryPool;
309 STATIC struct RDArgs * Parameters;
310 STATIC struct DiskObject * Icon;
312 STATIC struct WBStartup * WBStartup;
314 STATIC struct MinList ErrorList;
316 STATIC BOOL TranslateNames;
317 STATIC UBYTE A2M[256];
318 STATIC UBYTE M2A[256];
320 struct
322 KEY Workgroup;
323 KEY UserName;
324 KEY Password;
325 SWITCH ChangeCase;
326 SWITCH CaseSensitive;
327 SWITCH OmitHidden;
328 SWITCH Quiet;
329 KEY ClientName;
330 KEY ServerName;
331 KEY DeviceName;
332 KEY VolumeName;
333 NUMBER CacheSize;
334 NUMBER MaxTransmit;
335 NUMBER DebugLevel;
336 NUMBER TimeZoneOffset;
337 NUMBER DSTOffset;
338 SWITCH NetBIOSTransport;
339 SWITCH DumpSMB;
340 SWITCH UTF8;
341 KEY TranslationFile;
342 KEY Service;
343 } args;
345 STRPTR cmd_template =
346 "DOMAIN=WORKGROUP/K,"
347 "USER=USERNAME/K,"
348 "PASSWORD/K,"
349 "CHANGECASE/S,"
350 "CASE=CASESENSITIVE/S,"
351 "OMITHIDDEN/S,"
352 "QUIET/S,"
353 "CLIENT=CLIENTNAME/K,"
354 "SERVER=SERVERNAME/K,"
355 "DEVICE=DEVICENAME/K,"
356 "VOLUME=VOLUMENAME/K,"
357 "CACHE=CACHESIZE/N/K,"
358 "MAXTRANSMIT/N/K,"
359 "DEBUGLEVEL=DEBUG/N/K,"
360 "TZ=TIMEZONEOFFSET/N/K,"
361 "DST=DSTOFFSET/N/K,"
362 "NETBIOS/S,"
363 "DUMPSMB/S,"
364 "UTF8/S,"
365 "TRANSLATE=TRANSLATIONFILE/K,"
366 "SERVICE/A";
368 /****************************************************************************/
370 LONG _start(VOID)
372 LONG result = RETURN_OK;
374 #if !defined(__AROS__)
375 SysBase = (struct Library *)AbsExecBase;
377 #if defined(__amigaos4__)
379 IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
381 #endif /* __amigaos4__ */
382 #endif
384 FileSystemPort = &((*(struct Process *)FindTask(NULL)).pr_MsgPort);
386 /* Don't emit any debugging output before we are ready. */
387 SETDEBUGLEVEL(0);
389 /* Open the libraries we need and check
390 * whether we could get them.
392 DOSBase = OpenLibrary("dos.library",0);
394 #if defined(__amigaos4__)
396 if(DOSBase != NULL)
398 IDOS = (struct DOSIFace *)GetInterface(DOSBase, "main", 1, 0);
399 if(IDOS == NULL)
401 CloseLibrary(DOSBase);
402 DOSBase = NULL;
406 #endif /* __amigaos4__ */
408 UtilityBase = OpenLibrary("utility.library",37);
410 #if defined(__amigaos4__)
412 if(UtilityBase != NULL)
414 IUtility = (struct UtilityIFace *)GetInterface(UtilityBase, "main", 1, 0);
415 if(IUtility == NULL)
417 CloseLibrary(UtilityBase);
418 UtilityBase = NULL;
422 #endif /* __amigaos4__ */
424 if(UtilityBase == NULL || DOSBase == NULL || DOSBase->lib_Version < MINIMUM_OS_VERSION)
425 goto out;
427 /* This needs to be set up properly for ReportError()
428 * to work.
430 NewList((struct List *)&ErrorList);
432 if(Locale != NULL)
433 SHOWVALUE(Locale->loc_GMTOffset);
435 HandleFileSystem();
437 out:
439 Cleanup();
441 return(result);
444 /****************************************************************************/
446 #ifdef __AROS__
447 #define LocalPrintf(format,args...) Printf(format ,##args )
448 #else
449 LONG VARARGS68K
450 LocalPrintf(STRPTR format, ...)
452 va_list args;
453 LONG result;
455 #if defined(__amigaos4__)
457 va_startlinear(args,format);
458 result = VPrintf(format,va_getlinearva(args,APTR));
459 va_end(args);
461 #else
463 va_start(args,format);
464 result = VPrintf(format,args);
465 va_end(args);
467 #endif /* __amigaos4__ */
469 return(result);
471 #endif /* __AROS__ */
473 /****************************************************************************/
475 /* Obtain the descriptive text corresponding to an error number
476 * that may have been generated by the TCP/IP stack.
478 STRPTR
479 amitcp_strerror(int error)
481 struct TagItem tags[2];
482 STRPTR result;
484 ENTER();
486 tags[0].ti_Tag = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
487 tags[0].ti_Data = error;
488 tags[1].ti_Tag = TAG_END;
490 SocketBaseTagList(tags);
492 result = (STRPTR)tags[0].ti_Data;
494 RETURN(result);
495 return(result);
498 /****************************************************************************/
500 /* Return the descriptive text associated with a host lookup failure code. */
501 STRPTR
502 host_strerror(int error)
504 struct TagItem tags[2];
505 STRPTR result;
507 ENTER();
509 tags[0].ti_Tag = SBTM_GETVAL(SBTC_HERRNOSTRPTR);
510 tags[0].ti_Data = error;
511 tags[1].ti_Tag = TAG_END;
513 SocketBaseTagList(tags);
515 result = (STRPTR)tags[0].ti_Data;
517 RETURN(result);
518 return(result);
521 /****************************************************************************/
523 /* Compare two strings, either case sensitive or not
524 * sensitive to the case of the letters. How this is
525 * to be done is controlled by a global option. This
526 * routine is called whenever two SMB file names are
527 * to be compared.
529 LONG
530 CompareNames(STRPTR a,STRPTR b)
532 LONG result;
534 if(CaseSensitive)
535 result = strcmp(a,b);
536 else
537 result = Stricmp(a,b);
539 return(result);
542 /****************************************************************************/
544 /* Translate a string into all upper case characters. */
545 VOID
546 StringToUpper(STRPTR s)
548 UBYTE c;
550 while((c = (*s)) != '\0')
551 (*s++) = ToUpper(c);
554 /****************************************************************************/
556 /* Prepare the accumulated list of error messages for display
557 * and purge the contents of that list.
559 STATIC VOID
560 DisplayErrorList(VOID)
562 struct MinNode * last = NULL;
563 struct MinNode * mn;
564 STRPTR str = NULL;
565 STRPTR msg;
566 LONG len;
568 /* Determine how much memory will have to be
569 * allocated to hold all the accumulated
570 * error messages.
572 len = 0;
574 for(mn = ErrorList.mlh_Head ;
575 mn->mln_Succ != NULL ;
576 mn = mn->mln_Succ)
578 last = mn;
580 msg = (STRPTR)(mn + 1);
582 len += strlen(msg)+1;
585 /* Allocate the memory for the messages, then
586 * copy them there.
588 if(len > 0)
590 str = AllocVec(len,MEMF_ANY);
591 if(str != NULL)
593 str[0] = '\0';
595 for(mn = ErrorList.mlh_Head ;
596 mn->mln_Succ != NULL ;
597 mn = mn->mln_Succ)
599 msg = (STRPTR)(mn + 1);
601 strcat(str,msg);
602 if(mn != last)
603 strcat(str,"\n");
608 /* Purge the list. */
609 while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
610 FreeVec(mn);
612 /* Display the error messages. */
613 if(str != NULL)
615 IntuitionBase = OpenLibrary("intuition.library",37);
617 #if defined(__amigaos4__)
619 if(IntuitionBase != NULL)
621 IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, "main", 1, 0);
622 if(IIntuition == NULL)
624 CloseLibrary(IntuitionBase);
625 IntuitionBase = NULL;
629 #endif /* __amigaos4__ */
631 if(IntuitionBase != NULL)
633 struct EasyStruct es;
635 memset(&es,0,sizeof(es));
637 es.es_StructSize = sizeof(es);
638 es.es_Title = "SMB";
639 es.es_TextFormat = str;
640 es.es_GadgetFormat = "Ok";
642 EasyRequestArgs(NULL,&es,NULL,NULL);
645 FreeVec(str);
648 #if defined(__amigaos4__)
650 if(IIntuition != NULL)
652 DropInterface((struct Interface *)IIntuition);
653 IIntuition = NULL;
656 #endif /* __amigaos4__ */
658 CloseLibrary(IntuitionBase);
659 IntuitionBase = NULL;
662 #if !defined(__AROS__)
663 /* Add another error message to the list; the messages are
664 * collected so that they may be displayed together when
665 * necessary.
667 STATIC VOID
668 AddError(STRPTR fmt,APTR args)
670 LONG len;
672 len = CVSPrintf(fmt,args);
673 if(len > 0)
675 struct MinNode * mn;
677 mn = AllocVec(sizeof(*mn) + len,MEMF_ANY|MEMF_PUBLIC);
678 if(mn != NULL)
680 STRPTR msg = (STRPTR)(mn + 1);
682 VSPrintf(msg,fmt,args);
684 AddTail((struct List *)&ErrorList,(struct Node *)mn);
689 /****************************************************************************/
690 /* Report an error that has occured; if the program was not launched
691 * from Shell, error messages will be accumulated for later display.
693 VOID VARARGS68K
694 ReportError(STRPTR fmt,...)
696 if(NOT Quiet)
698 va_list args;
700 if(WBStartup != NULL)
702 #if defined(__amigaos4__)
704 va_startlinear(args,fmt);
705 AddError(fmt,va_getlinearva(args,APTR));
706 va_end(args);
708 #else
710 va_start(args,fmt);
711 AddError(fmt,args);
712 va_end(args);
714 #endif /* __amigaos4__ */
716 else
718 UBYTE program_name[MAX_FILENAME_LEN];
720 GetProgramName(program_name,sizeof(program_name));
722 LocalPrintf("%s: ",FilePart(program_name));
724 #if defined(__amigaos4__)
726 va_startlinear(args,fmt);
727 VPrintf(fmt,va_getlinearva(args,APTR));
728 va_end(args);
730 #else
732 va_start(args,fmt);
733 VPrintf(fmt,args);
734 va_end(args);
736 #endif /* __amigaos4__ */
738 LocalPrintf("\n");
742 #endif
744 /****************************************************************************/
746 /* Release memory allocated from the global pool. */
747 VOID
748 FreeMemory(APTR address)
750 if(address != NULL)
752 ULONG * mem = address;
754 #if DEBUG
756 if(GETDEBUGLEVEL() > 0)
757 memset(address,0xA3,mem[-1] - sizeof(*mem));
759 #endif /* DEBUG */
761 FreePooled(MemoryPool,&mem[-1],mem[-1]);
765 /* Allocate memory from the global pool. */
766 APTR
767 AllocateMemory(ULONG size)
769 APTR result = NULL;
771 if(size > 0)
773 ULONG * mem;
775 size = (sizeof(*mem) + size + 7) & ~7UL;
777 mem = AllocPooled(MemoryPool,size);
778 if(mem != NULL)
780 (*mem++) = size;
782 #if DEBUG
784 if(GETDEBUGLEVEL() > 0)
785 memset(mem,0xA5,mem[-1] - sizeof(*mem));
787 #endif /* DEBUG */
789 result = mem;
793 return(result);
796 /****************************************************************************/
798 /* Obtain the number of seconds to add to the current time
799 * to translate local time into UTC.
801 LONG
802 GetTimeZoneDelta(VOID)
804 LONG seconds;
806 if(OverrideLocaleTimeZone)
808 seconds = 60 * TimeZoneOffset;
810 else if (Locale != NULL)
812 /* The GMT offset actually is the number of minutes to add to
813 * the local time to yield Greenwich Mean Time. It is negative
814 * for all time zones east of the Greenwich meridian and
815 * positive for all time zones west of it.
817 seconds = 60 * Locale->loc_GMTOffset;
819 else
821 seconds = 0;
824 return(seconds + DSTOffset);
827 /****************************************************************************/
829 /* Obtain the current time, in standard Unix format, adjusted for the
830 * local time zone.
832 ULONG
833 GetCurrentTime(VOID)
835 struct timeval tv;
836 ULONG result;
838 GetSysTime((APTR)&tv);
840 result = UNIX_TIME_OFFSET + GetTimeZoneDelta() + tv.tv_secs;
842 return(result);
845 /****************************************************************************/
847 /* Fill in a 'tm' type time specification with time information
848 * corresponding to the number of seconds provided. Input is
849 * in Unix format.
851 VOID
852 GMTime(time_t seconds,struct tm * tm)
854 struct ClockData clock_data;
856 if(seconds < UNIX_TIME_OFFSET)
857 seconds = 0;
858 else
859 seconds -= UNIX_TIME_OFFSET;
861 Amiga2Date(seconds,&clock_data);
863 memset(tm,0,sizeof(*tm));
865 tm->tm_sec = clock_data.sec;
866 tm->tm_min = clock_data.min;
867 tm->tm_hour = clock_data.hour;
868 tm->tm_mday = clock_data.mday;
869 tm->tm_mon = clock_data.month - 1;
870 tm->tm_year = clock_data.year - 1900;
873 /* Calculate the number of seconds that have passed since January 1st 1970
874 * based upon the time specification provided. Output is in Unix format.
876 time_t
877 MakeTime(const struct tm * const tm)
879 struct ClockData clock_data;
880 time_t seconds;
882 clock_data.sec = tm->tm_sec;
883 clock_data.min = tm->tm_min;
884 clock_data.hour = tm->tm_hour;
885 clock_data.mday = tm->tm_mday;
886 clock_data.month = tm->tm_mon + 1;
887 clock_data.year = tm->tm_year + 1900;
889 seconds = Date2Amiga(&clock_data) + UNIX_TIME_OFFSET;
891 return(seconds);
894 /****************************************************************************/
896 #if !defined(__AROS__)
897 struct FormatContext
899 UBYTE * fc_Buffer;
900 LONG fc_Size;
903 /****************************************************************************/
905 STATIC VOID ASM
906 CountChar(REG(a3,struct FormatContext * fc))
908 fc->fc_Size++;
911 /* Count the number of characters SPrintf() would put into a string. */
912 STATIC LONG
913 CVSPrintf(STRPTR format_string,APTR args)
915 struct FormatContext fc;
917 fc.fc_Size = 0;
919 RawDoFmt((STRPTR)format_string,args,(VOID (*)())CountChar,&fc);
921 return(fc.fc_Size);
924 /****************************************************************************/
926 STATIC VOID ASM
927 StuffChar(REG(d0,UBYTE c),REG(a3,struct FormatContext * fc))
929 (*fc->fc_Buffer++) = c;
932 STATIC VOID
933 VSPrintf(STRPTR buffer, STRPTR formatString, APTR args)
935 struct FormatContext fc;
937 fc.fc_Buffer = buffer;
939 RawDoFmt(formatString,args,(VOID (*)())StuffChar,&fc);
942 /****************************************************************************/
944 /* Format a string for output. */
945 VOID VARARGS68K
946 SPrintf(STRPTR buffer, STRPTR formatString,...)
948 va_list varArgs;
950 #if defined(__amigaos4__)
952 va_startlinear(varArgs,formatString);
953 VSPrintf(buffer,formatString,va_getlinearva(varArgs,APTR));
954 va_end(varArgs);
956 #else
958 va_start(varArgs,formatString);
959 VSPrintf(buffer,formatString,varArgs);
960 va_end(varArgs);
962 #endif /* __amigaos4__ */
964 #endif
966 /****************************************************************************/
968 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
969 * Thanks very much, Chris!
971 struct addr_entry
973 unsigned short flags;
974 unsigned char address[4];
977 struct nmb_header
979 unsigned short name_trn_id;
980 unsigned short flags;
981 unsigned short qdcount;
982 unsigned short ancount;
983 unsigned short nscount;
984 unsigned short arcount;
987 static UBYTE *
988 L1_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx)
990 int i = 0;
991 int j = 0;
992 int k;
994 while(('\0' != name[i]) && (i < 15))
996 k = ToUpper(name[i]);
997 i++;
998 dst[j++] = 'A' + ((k & 0xF0) >> 4);
999 dst[j++] = 'A' + (k & 0x0F);
1002 i = 'A' + ((pad & 0xF0) >> 4);
1003 k = 'A' + (pad & 0x0F);
1005 while(j < 30)
1007 dst[j++] = i;
1008 dst[j++] = k;
1011 dst[30] = 'A' + ((sfx & 0xF0) >> 4);
1012 dst[31] = 'A' + (sfx & 0x0F);
1013 dst[32] = '\0';
1015 return(dst);
1018 static int
1019 L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, const UBYTE * scope)
1021 int lenpos;
1022 int i;
1023 int j;
1025 if(NULL == L1_Encode(&dst[1], name, pad, sfx))
1026 return(-1);
1028 dst[0] = 0x20;
1029 lenpos = 33;
1031 if('\0' != (*scope))
1035 for(i = 0, j = (lenpos + 1);
1036 ('.' != scope[i]) && ('\0' != scope[i]);
1037 i++, j++)
1039 dst[j] = ToUpper(scope[i]);
1042 dst[lenpos] = (UBYTE)i;
1043 lenpos += i + 1;
1044 scope += i;
1046 while('.' == (*scope++));
1048 dst[lenpos] = '\0';
1051 return(lenpos + 1);
1055 BroadcastNameQuery(char *name, char *scope, UBYTE *address)
1057 static const UBYTE header[12] =
1059 0x07, 0xB0, /* 1964 == 0x07B0. */
1060 0x01, 0x10, /* Binary 0 0000 0010001 0000 */
1061 0x00, 0x01, /* One name query. */
1062 0x00, 0x00, /* Zero answers. */
1063 0x00, 0x00, /* Zero authorities. */
1064 0x00, 0x00 /* Zero additional. */
1067 static const UBYTE query_tail[4] =
1069 0x00, 0x20,
1070 0x00, 0x01
1073 struct timeval tv;
1074 fd_set read_fds;
1075 int sock_fd;
1076 int option_true = 1;
1077 struct sockaddr_in sox;
1078 struct nmb_header nmb_header;
1079 UBYTE buffer[512];
1080 int total_len;
1081 int i,n;
1082 int result;
1083 struct servent * s;
1085 ENTER();
1087 sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
1088 if(sock_fd < 0)
1090 SHOWMSG("couldn't get the socket");
1091 result = (-errno);
1092 goto out;
1095 if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &option_true, sizeof(option_true)) < 0)
1097 SHOWMSG("couldn't enable the broadcast option");
1098 result = (-errno);
1099 goto out;
1102 sox.sin_family = AF_INET;
1103 sox.sin_addr.s_addr = htonl(0xFFFFFFFF);
1105 s = getservbyname("netbios-ns","udp");
1106 if(s != NULL)
1107 sox.sin_port = s->s_port;
1108 else
1109 sox.sin_port = htons(137);
1111 memcpy(buffer, header, (total_len = sizeof(header)));
1113 n = L2_Encode(&buffer[total_len], name, ' ', '\0', scope);
1114 if(n < 0)
1116 SHOWMSG("name encoding failed");
1117 result = (-EINVAL);
1118 goto out;
1121 total_len += n;
1122 memcpy(&buffer[total_len], query_tail, sizeof(query_tail));
1123 total_len += sizeof(query_tail);
1125 result = (-ENOENT);
1126 n = 0;
1128 /* Send the query packet; retry five times with a one second
1129 * delay in between.
1131 for(i = 0 ; i < 5 ; i++)
1133 if(sendto(sock_fd, (void *) buffer, total_len, 0, (struct sockaddr *)&sox, sizeof(struct sockaddr_in)) < 0)
1135 SHOWMSG("could not send the packet");
1136 result = (-errno);
1137 goto out;
1140 /* Wait for a response to arrive. */
1141 tv.tv_secs = 1;
1142 tv.tv_micro = 0;
1144 FD_ZERO(&read_fds);
1145 FD_SET(sock_fd,&read_fds);
1147 if(WaitSelect(sock_fd+1, &read_fds, NULL, NULL, &tv, NULL) > 0)
1149 n = recvfrom(sock_fd, buffer, sizeof(buffer), 0, NULL, NULL);
1150 if(n < 0)
1152 SHOWMSG("could not pick up the response packet");
1153 result = (-errno);
1154 goto out;
1156 else if (n > 0)
1158 break;
1163 /* Did we get anything at all? */
1164 if(n > (int)sizeof(nmb_header))
1166 /* Check whether the query was successful. */
1167 memcpy(&nmb_header, buffer, sizeof(nmb_header));
1168 if((nmb_header.flags & 0xF) == OK)
1170 /* Find the NB/IP fields which directly follow
1171 * the name.
1173 for(i = sizeof(header) + strlen(&buffer[sizeof(header)])+1 ; i < n - (int)sizeof(query_tail) ; i++)
1175 if(memcmp(&buffer[i], query_tail, sizeof(query_tail)) == SAME)
1177 int start;
1179 /* This should be the start of the interesting bits;
1180 * we skip the NB/IP fields and the TTL field.
1182 start = i + sizeof(query_tail) + sizeof(long);
1183 if(start < n)
1185 unsigned short read_len;
1186 struct addr_entry addr_entry;
1188 /* This should be the read length. */
1189 memcpy(&read_len, &buffer[start], 2);
1191 /* Is there any useful and readable data attached? */
1192 if(read_len >= sizeof(addr_entry) &&
1193 start + (int)sizeof(read_len) + (int)sizeof(addr_entry) <= n)
1195 /* Copy a single address entry; this should be
1196 * just the one we need.
1198 memcpy(&addr_entry, &buffer[start + sizeof(read_len)], sizeof(addr_entry));
1200 /* Copy the address field (IPv4 only). */
1201 memcpy(address, addr_entry.address, 4);
1203 result = 0;
1207 break;
1213 out:
1215 if(sock_fd >= 0)
1216 CloseSocket(sock_fd);
1218 RETURN(result);
1219 return(result);
1222 /****************************************************************************/
1224 /* Send a disk change notification message which will be picked up
1225 * by all applications that listen for this kind of event, e.g.
1226 * Workbench.
1228 STATIC VOID
1229 SendDiskChange(ULONG class)
1231 struct IOStdReq * input_request = NULL;
1232 struct MsgPort * input_port;
1233 struct InputEvent ie;
1235 ENTER();
1237 input_port = CreateMsgPort();
1238 if(input_port == NULL)
1239 goto out;
1241 input_request = (struct IOStdReq *)CreateIORequest(input_port,sizeof(*input_request));
1242 if(input_request == NULL)
1243 goto out;
1245 if(OpenDevice("input.device",0,(struct IORequest *)input_request,0) != OK)
1246 goto out;
1248 memset(&ie,0,sizeof(ie));
1250 ie.ie_Class = class;
1251 ie.ie_Qualifier = IEQUALIFIER_MULTIBROADCAST;
1253 GetSysTime(&ie.ie_TimeStamp);
1255 input_request->io_Command = IND_WRITEEVENT;
1256 input_request->io_Data = &ie;
1257 input_request->io_Length = sizeof(ie);
1259 DoIO((struct IORequest *)input_request);
1261 out:
1263 if(input_request != NULL)
1265 if(input_request->io_Device != NULL)
1266 CloseDevice((struct IORequest *)input_request);
1268 DeleteIORequest((struct IORequest *)input_request);
1271 DeleteMsgPort(input_port);
1273 LEAVE();
1276 /****************************************************************************/
1278 /* Find the file node corresponding to a given name,
1279 * skipping a particular entry if necessary.
1281 STATIC struct FileNode *
1282 FindFileNode(STRPTR name,struct FileNode * skip)
1284 struct FileNode * result = NULL;
1285 struct FileNode * fn;
1287 for(fn = (struct FileNode *)FileList.mlh_Head ;
1288 fn->fn_MinNode.mln_Succ != NULL ;
1289 fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
1291 if(fn != skip && CompareNames(name,fn->fn_FullName) == SAME)
1293 result = fn;
1294 break;
1298 return(result);
1301 /* Find the lock node corresponding to a given name,
1302 * skipping a particular entry if necessary.
1304 STATIC struct LockNode *
1305 FindLockNode(STRPTR name,struct LockNode * skip)
1307 struct LockNode * result = NULL;
1308 struct LockNode * ln;
1310 for(ln = (struct LockNode *)LockList.mlh_Head ;
1311 ln->ln_MinNode.mln_Succ != NULL ;
1312 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
1314 if(ln != skip && CompareNames(name,ln->ln_FullName) == SAME)
1316 result = ln;
1317 break;
1321 return(result);
1324 /* Check whether a new reference to be made to a named
1325 * file will cause a conflict of access modes. No two
1326 * files and locks may refer to the same object if
1327 * either of these references is made in exclusive
1328 * mode. This is the case which this function is
1329 * trying to avoid.
1331 STATIC LONG
1332 CheckAccessModeCollision(STRPTR name,LONG mode)
1334 struct LockNode * ln;
1335 struct FileNode * fn;
1336 LONG error = OK;
1338 ENTER();
1339 SHOWSTRING(name);
1341 fn = FindFileNode(name,NULL);
1342 if(fn != NULL)
1344 if(mode != SHARED_LOCK || fn->fn_Mode != SHARED_LOCK)
1346 D(("collides with '%s'",fn->fn_FullName));
1347 error = ERROR_OBJECT_IN_USE;
1348 goto out;
1352 ln = FindLockNode(name,NULL);
1353 if(ln != NULL)
1355 if(mode != SHARED_LOCK || ln->ln_FileLock.fl_Access != SHARED_LOCK)
1357 D(("collides with '%s'",ln->ln_FullName));
1358 error = ERROR_OBJECT_IN_USE;
1359 goto out;
1363 out:
1365 RETURN(error);
1366 return(error);
1369 /* Find out whether there already exists a reference to a
1370 * certain file or directory.
1372 STATIC LONG
1373 NameAlreadyInUse(STRPTR name)
1375 LONG error = OK;
1377 ENTER();
1379 if(FindFileNode(name,NULL) != NULL)
1381 error = ERROR_OBJECT_IN_USE;
1382 goto out;
1385 if(FindLockNode(name,NULL) != NULL)
1387 error = ERROR_OBJECT_IN_USE;
1388 goto out;
1391 out:
1393 RETURN(error);
1394 return(error);
1397 /* Check whether an Amiga file name uses special characters which
1398 * should be avoided when used with the SMB file sharing protocol.
1400 STATIC BOOL
1401 IsReservedName(STRPTR name)
1403 BOOL result = FALSE;
1405 /* Disallow "." and "..". */
1406 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
1408 result = TRUE;
1410 else
1412 UBYTE c;
1414 /* Disallow the use of the backslash in file names. */
1415 while((c = (*name++)) != '\0')
1417 if(c == SMB_PATH_SEPARATOR)
1419 result = TRUE;
1420 break;
1425 return(result);
1428 /****************************************************************************/
1430 /* Convert a POSIX error code into an AmigaDOS error code. */
1431 STATIC LONG
1432 MapErrnoToIoErr(int error)
1434 /* Not all of these mappings make good sense; bear in mind that
1435 * POSIX covers more than a hundred different error codes
1436 * whereas with AmigaDOS we're stranded with a measly 48...
1438 STATIC const LONG Map[][2] =
1440 { EPERM, ERROR_OBJECT_NOT_FOUND }, /* Operation not permitted */
1441 { ENOENT, ERROR_OBJECT_NOT_FOUND }, /* No such file or directory */
1442 { ESRCH, ERROR_OBJECT_NOT_FOUND }, /* No such process */
1443 { EINTR, ERROR_BREAK }, /* Interrupted system call */
1444 { EIO, ERROR_OBJECT_IN_USE }, /* Input/output error */
1445 { E2BIG, ERROR_TOO_MANY_ARGS }, /* Argument list too long */
1446 { EBADF, ERROR_INVALID_LOCK }, /* Bad file descriptor */
1447 { ENOMEM, ERROR_NO_FREE_STORE }, /* Cannot allocate memory */
1448 { EACCES, ERROR_OBJECT_NOT_FOUND}, /* Permission denied */
1449 { ENOTBLK, ERROR_OBJECT_WRONG_TYPE }, /* Block device required */
1450 { EBUSY, ERROR_OBJECT_IN_USE }, /* Device busy */
1451 { EEXIST, ERROR_OBJECT_EXISTS }, /* File exists */
1452 { EXDEV, ERROR_NOT_IMPLEMENTED }, /* Cross-device link */
1453 { ENOTDIR, ERROR_OBJECT_WRONG_TYPE }, /* Not a directory */
1454 { EISDIR, ERROR_OBJECT_WRONG_TYPE }, /* Is a directory */
1455 { EINVAL, ERROR_BAD_NUMBER }, /* Invalid argument */
1456 { EFBIG, ERROR_DISK_FULL }, /* File too large */
1457 { ENOSPC, ERROR_DISK_FULL }, /* No space left on device */
1458 { ESPIPE, ERROR_SEEK_ERROR }, /* Illegal seek */
1459 { EROFS, ERROR_WRITE_PROTECTED }, /* Read-only file system */
1460 { EMLINK, ERROR_TOO_MANY_LEVELS }, /* Too many links */
1461 { ENOTSOCK, ERROR_OBJECT_WRONG_TYPE }, /* Socket operation on non-socket */
1462 { EDESTADDRREQ, ERROR_REQUIRED_ARG_MISSING }, /* Destination address required */
1463 { EMSGSIZE, ERROR_LINE_TOO_LONG }, /* Message too long */
1464 { EPROTOTYPE, ERROR_BAD_TEMPLATE }, /* Protocol wrong type for socket */
1465 { ENOPROTOOPT, ERROR_NOT_IMPLEMENTED }, /* Protocol not available */
1466 { EPROTONOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Protocol not supported */
1467 { ESOCKTNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Socket type not supported */
1468 { EOPNOTSUPP, ERROR_NOT_IMPLEMENTED }, /* Operation not supported */
1469 { EPFNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Protocol family not supported */
1470 { EAFNOSUPPORT, ERROR_NOT_IMPLEMENTED }, /* Address family not supported by protocol family */
1471 { EADDRINUSE, ERROR_OBJECT_IN_USE }, /* Address already in use */
1472 { EADDRNOTAVAIL, ERROR_OBJECT_NOT_FOUND }, /* Can't assign requested address */
1473 { ENETDOWN, ERROR_OBJECT_NOT_FOUND }, /* Network is down */
1474 { ENETUNREACH, ERROR_OBJECT_NOT_FOUND }, /* Network is unreachable */
1475 { ENETRESET, ERROR_OBJECT_NOT_FOUND }, /* Network dropped connection on reset */
1476 { ECONNABORTED, ERROR_OBJECT_NOT_FOUND }, /* Software caused connection abort */
1477 { ECONNRESET, ERROR_OBJECT_NOT_FOUND }, /* Connection reset by peer */
1478 { ENOBUFS, ERROR_DISK_FULL }, /* No buffer space available */
1479 { EISCONN, ERROR_OBJECT_IN_USE }, /* Socket is already connected */
1480 { ENOTCONN, ERROR_OBJECT_WRONG_TYPE }, /* Socket is not connected */
1481 { ESHUTDOWN, ERROR_INVALID_LOCK }, /* Can't send after socket shutdown */
1482 { ECONNREFUSED, ERROR_OBJECT_IN_USE }, /* Connection refused */
1483 { ELOOP, ERROR_TOO_MANY_LEVELS }, /* Too many levels of symbolic links */
1484 { ENAMETOOLONG, ERROR_LINE_TOO_LONG }, /* File name too long */
1485 { EHOSTDOWN, ERROR_OBJECT_NOT_FOUND }, /* Host is down */
1486 { EHOSTUNREACH, ERROR_OBJECT_NOT_FOUND }, /* No route to host */
1487 { ENOTEMPTY, ERROR_DIRECTORY_NOT_EMPTY }, /* Directory not empty */
1488 { EPROCLIM, ERROR_TASK_TABLE_FULL }, /* Too many processes */
1489 { EUSERS, ERROR_TASK_TABLE_FULL }, /* Too many users */
1490 { EDQUOT, ERROR_DISK_FULL }, /* Disc quota exceeded */
1491 { ENOLCK, ERROR_NOT_IMPLEMENTED }, /* no locks available */
1492 { -1, -1 }
1495 LONG result = ERROR_ACTION_NOT_KNOWN;
1496 LONG i;
1498 ENTER();
1500 if(error < 0)
1501 error = (-error);
1503 for(i = 0 ; Map[i][0] != -1 ; i++)
1505 if(Map[i][0] == error)
1507 result = Map[i][1];
1508 break;
1512 RETURN(result);
1513 return(result);
1516 /****************************************************************************/
1518 /* Translate a BCPL style file name (i.e. length is in the first byte)
1519 * via a mapping table.
1521 INLINE STATIC VOID
1522 TranslateBName(UBYTE * name,UBYTE * map)
1524 LONG len;
1525 UBYTE c;
1527 #if !defined(N__AROS__)
1528 len = (*name++);
1529 #else
1530 len = AROS_BSTR_strlen(name);
1531 name = AROS_BSTR_ADDR(name);
1532 #endif
1533 while(len-- > 0)
1535 c = (*name);
1537 (*name++) = map[c];
1541 /* Translate a NUL terminated file name via a mapping table. */
1542 INLINE STATIC VOID
1543 TranslateCName(UBYTE * name,UBYTE * map)
1545 UBYTE c;
1547 while((c = (*name)) != '\0')
1548 (*name++) = map[c];
1551 /****************************************************************************/
1553 /* Remove a DosList entry using the proper protocols. Note that
1554 * this function can fail!
1556 STATIC BOOL
1557 ReallyRemoveDosEntry(struct DosList * entry)
1559 struct Message * mn;
1560 struct MsgPort * port;
1561 struct DosList * dl;
1562 BOOL result = FALSE;
1563 LONG kind,i;
1565 if(entry->dol_Type == DLT_DEVICE)
1566 kind = LDF_DEVICES;
1567 else
1568 kind = LDF_VOLUMES;
1570 port = entry->dol_Task;
1572 for(i = 0 ; i < 100 ; i++)
1574 dl = AttemptLockDosList(LDF_WRITE|kind);
1575 if(((IPTR)dl) <= 1)
1576 dl = NULL;
1578 if(dl != NULL)
1580 RemDosEntry(entry);
1582 UnLockDosList(LDF_WRITE|kind);
1584 result = TRUE;
1586 break;
1589 while((mn = GetMsg(port)) != NULL)
1590 ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
1592 Delay(TICKS_PER_SECOND / 10);
1595 return(result);
1598 /****************************************************************************/
1600 /* Release all resources allocated by the Setup() routine. */
1601 STATIC VOID
1602 Cleanup(VOID)
1604 BOOL send_disk_change = FALSE;
1606 ENTER();
1608 /* If any errors have cropped up, display them now before
1609 * we call it quits.
1611 DisplayErrorList();
1613 if(Parameters != NULL)
1615 FreeArgs(Parameters);
1616 Parameters = NULL;
1619 if(Icon != NULL)
1621 FreeDiskObject(Icon);
1622 Icon = NULL;
1625 if(ServerData != NULL)
1627 smba_disconnect(ServerData);
1628 ServerData = NULL;
1631 if(DeviceNode != NULL)
1633 if(DeviceNodeAdded)
1635 if(ReallyRemoveDosEntry(DeviceNode))
1636 FreeDosEntry(DeviceNode);
1638 else
1640 FreeDosEntry(DeviceNode);
1643 DeviceNode = NULL;
1646 if(VolumeNode != NULL)
1648 if(VolumeNodeAdded)
1650 if(ReallyRemoveDosEntry(VolumeNode))
1651 FreeDosEntry(VolumeNode);
1653 send_disk_change = TRUE;
1655 else
1657 FreeDosEntry(VolumeNode);
1660 VolumeNode = NULL;
1663 if(FileSystemPort != NULL)
1665 struct Message * mn;
1667 /* Return all queued packets; there should be none, though. */
1668 while((mn = GetMsg(FileSystemPort)) != NULL)
1669 ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
1671 #if !defined(__AROS__)
1672 /* AROS codes use message port from file system process */
1673 DeleteMsgPort(FileSystemPort);
1674 #endif
1675 FileSystemPort = NULL;
1678 if(WBStartup == NULL && send_disk_change)
1679 SendDiskChange(IECLASS_DISKREMOVED);
1681 #if defined(__amigaos4__)
1683 if(ITimer != NULL)
1685 DropInterface((struct Interface *)ITimer);
1686 ITimer = NULL;
1689 #endif /* __amigaos4__ */
1691 if(TimerBase != NULL)
1693 CloseDevice((struct IORequest *)&TimerRequest);
1694 TimerBase = NULL;
1697 #if defined(__amigaos4__)
1699 if(ISocket != NULL)
1701 DropInterface((struct Interface *)ISocket);
1702 ISocket = NULL;
1705 #endif /* __amigaos4__ */
1707 if(SocketBase != NULL)
1709 CloseLibrary(SocketBase);
1710 SocketBase = NULL;
1713 #if defined(__amigaos4__)
1715 if(IIcon != NULL)
1717 DropInterface((struct Interface *)IIcon);
1718 IIcon = NULL;
1721 #endif /* __amigaos4__ */
1723 if(IconBase != NULL)
1725 CloseLibrary(IconBase);
1726 IconBase = NULL;
1729 if(Locale != NULL)
1731 CloseLocale(Locale);
1732 Locale = NULL;
1735 #if defined(__amigaos4__)
1737 if(ILocale != NULL)
1739 DropInterface((struct Interface *)ILocale);
1740 ILocale = NULL;
1743 #endif /* __amigaos4__ */
1745 if(LocaleBase != NULL)
1747 CloseLibrary(LocaleBase);
1748 LocaleBase = NULL;
1751 if(MemoryPool != NULL)
1753 DeletePool(MemoryPool);
1754 MemoryPool = NULL;
1757 LEAVE();
1760 /****************************************************************************/
1762 /* Allocate all the necessary resources to get going. */
1763 STATIC BOOL
1764 Setup(
1765 STRPTR opt_password,
1766 BOOL opt_changecase,
1767 LONG * opt_time_zone_offset,
1768 LONG * opt_dst_offset,
1769 STRPTR translation_file)
1771 BOOL result = FALSE;
1772 int error = OK;
1773 LONG i;
1775 ENTER();
1777 NewList((struct List *)&FileList);
1778 NewList((struct List *)&LockList);
1780 MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC,4096,4096);
1781 if(MemoryPool == NULL)
1783 ReportError("Could not create memory pool.");
1784 goto out;
1787 LocaleBase = OpenLibrary("locale.library",38);
1789 #if defined(__amigaos4__)
1791 if(LocaleBase != NULL)
1793 ILocale = (struct LocaleIFace *)GetInterface(LocaleBase, "main", 1, 0);
1794 if(ILocale == NULL)
1796 CloseLibrary(LocaleBase);
1797 LocaleBase = NULL;
1801 #endif /* __amigaos4__ */
1803 if(LocaleBase != NULL)
1804 Locale = OpenLocale(NULL);
1806 if(opt_time_zone_offset != NULL)
1808 TimeZoneOffset = (*opt_time_zone_offset);
1809 OverrideLocaleTimeZone = TRUE;
1812 if(opt_dst_offset != NULL)
1813 DSTOffset = -60 * (*opt_dst_offset);
1815 memset(&TimerRequest,0,sizeof(TimerRequest));
1817 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest,0) != OK)
1819 ReportError("Could not open 'timer.device'.");
1820 goto out;
1823 TimerBase = (struct Library *)TimerRequest.tr_node.io_Device;
1825 #if defined(__amigaos4__)
1827 if(TimerBase != NULL)
1829 ITimer = (struct TimerIFace *)GetInterface(TimerBase, "main", 1, 0);
1830 if(ITimer == NULL)
1832 ReportError("Could not open 'timer.device'.");
1833 goto out;
1837 #endif /* __amigaos4__ */
1839 SocketBase = OpenLibrary("bsdsocket.library",3);
1841 #if defined(__amigaos4__)
1843 if(SocketBase != NULL)
1845 ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, 0);
1846 if(ISocket == NULL)
1848 CloseLibrary(SocketBase);
1849 SocketBase = NULL;
1853 #endif /* __amigaos4__ */
1855 if(SocketBase == NULL)
1857 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
1858 goto out;
1861 error = SocketBaseTags(
1862 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), &errno,
1863 SBTM_SETVAL(SBTC_HERRNOLONGPTR), &h_errno,
1864 SBTM_SETVAL(SBTC_LOGTAGPTR), HandlerName,
1865 SBTM_SETVAL(SBTC_BREAKMASK), SIGBREAKF_CTRL_C,
1866 TAG_END);
1867 if(error != OK)
1869 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
1870 goto out;
1873 if(opt_changecase)
1875 for(i = 0 ; i < (LONG)strlen(opt_password) ; i++)
1876 opt_password[i] = ToUpper(opt_password[i]);
1879 TranslateNames = FALSE;
1881 /* Read the translation file, if possible. */
1882 if(translation_file != NULL)
1884 STRPTR msg = NULL;
1885 BPTR file;
1887 error = OK;
1889 file = Open(translation_file,MODE_OLDFILE);
1890 if(file != ZERO)
1892 if(Read(file,A2M,256) != 256 ||
1893 Read(file,M2A,256) != 256)
1895 msg = "Could not read translation file";
1896 error = IoErr();
1899 Close(file);
1901 else
1903 msg = "Could not open translation file";
1904 error = IoErr();
1907 if(msg == NULL)
1909 TranslateNames = TRUE;
1911 else
1913 UBYTE description[100];
1915 Fault(error,NULL,description,sizeof(description));
1916 for(i = ((int)strlen(description)) - 1 ; i >= 0 ; i--)
1918 if(description[i] == '\n')
1919 description[i] = '\0';
1922 ReportError("%s '%s' (%ld, %s).",msg,translation_file,error,description);
1923 goto out;
1927 result = TRUE;
1929 out:
1931 RETURN(result);
1932 return(result);
1935 /****************************************************************************/
1938 /* Make connection to server and make a volume for it. */
1939 STATIC BOOL
1940 AddVolume(
1941 STRPTR device_name,
1942 STRPTR volume_name,
1943 STRPTR service,
1944 STRPTR workgroup,
1945 STRPTR username,
1946 STRPTR opt_password,
1947 STRPTR opt_clientname,
1948 STRPTR opt_servername,
1949 int opt_cachesize,
1950 int opt_max_transmit,
1951 BOOL opt_raw_smb)
1953 BOOL result = FALSE;
1954 struct DosList * dl;
1955 int error = OK;
1956 STRPTR actual_volume_name;
1957 LONG actual_volume_name_len;
1958 UBYTE name[MAX_FILENAME_LEN];
1959 BOOL device_exists = FALSE;
1960 LONG len,i;
1962 ENTER();
1964 error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,opt_max_transmit,opt_raw_smb,&ServerData);
1965 if(error < 0)
1966 goto out;
1968 /* If a device name was provided, check whether it is
1969 * well-formed.
1971 if(device_name != NULL)
1973 len = strlen(device_name);
1974 if(len > 255)
1975 len = 255;
1977 for(i = 0 ; i < len ; i++)
1979 if(device_name[i] == '/')
1981 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
1982 goto out;
1986 /* Lose any trailing colon characters. */
1987 for(i = len-1 ; i >= 0 ; i--)
1989 if(device_name[i] == ':')
1990 len = i;
1993 if(len == 0)
1995 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
1996 goto out;
1999 memcpy(name,device_name,len);
2000 name[len] = '\0';
2002 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2004 if(FindDosEntry(dl,name,LDF_DEVICES) != NULL)
2005 device_exists = TRUE;
2007 else
2009 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2011 /* Find a unique device name. */
2012 for(i = 0 ; i < 100 ; i++)
2014 SPrintf(name,"SMBFS%ld",(long)i);
2016 device_exists = (BOOL)(FindDosEntry(dl,name,LDF_DEVICES) != NULL);
2017 if(NOT device_exists)
2019 device_name = name;
2020 break;
2025 if(device_exists)
2027 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2029 ReportError("Device name '%s:' is already taken.",device_name);
2030 goto out;
2033 /* Finally, create the device node. */
2034 DeviceNode = MakeDosEntry(name,DLT_DEVICE);
2035 if(DeviceNode == NULL)
2037 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2039 ReportError("Could not create device node.");
2040 goto out;
2043 DeviceNode->dol_Task = FileSystemPort;
2045 /* Examine the volume name; make sure that it is
2046 * well-formed.
2048 if(volume_name == NULL)
2049 actual_volume_name = device_name;
2050 else
2051 actual_volume_name = volume_name;
2053 actual_volume_name_len = strlen(actual_volume_name);
2054 if(actual_volume_name_len > 255)
2055 actual_volume_name_len = 255;
2057 for(i = 0 ; i < actual_volume_name_len ; i++)
2059 if(actual_volume_name[i] == '/')
2061 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2063 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2064 goto out;
2068 /* Lose any trailing colon characters. */
2069 for(i = actual_volume_name_len-1 ; i >= 0 ; i--)
2071 if(actual_volume_name[i] == ':')
2072 actual_volume_name_len = i;
2075 if(actual_volume_name_len == 0)
2077 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2079 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2080 goto out;
2083 /* Now, finally, take care of the volume name. */
2084 memcpy(name,actual_volume_name,actual_volume_name_len);
2085 name[actual_volume_name_len] = '\0';
2087 VolumeNode = MakeDosEntry(name,DLT_VOLUME);
2088 if(VolumeNode == NULL)
2090 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2092 ReportError("Could not create volume node.");
2093 goto out;
2096 VolumeNode->dol_Task = FileSystemPort;
2097 DateStamp(&VolumeNode->dol_misc.dol_volume.dol_VolumeDate);
2098 VolumeNode->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
2100 if(DeviceNode != NULL)
2102 AddDosEntry(DeviceNode);
2104 DeviceNodeAdded = TRUE;
2107 /* Note: we always need the volume node to make some file
2108 * system operations safe (e.g. Lock()), but we may
2109 * not always need to make it visible.
2111 if(volume_name != NULL && VolumeNode != NULL)
2113 AddDosEntry(VolumeNode);
2115 VolumeNodeAdded = TRUE;
2118 /* And that concludes the mounting operation. */
2119 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2121 /* Tell Workbench and friends to update their volume lists. */
2122 if(VolumeNodeAdded)
2123 SendDiskChange(IECLASS_DISKINSERTED);
2125 result = TRUE;
2127 out:
2129 RETURN(result);
2130 return(result);
2133 /****************************************************************************/
2135 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2136 INLINE STATIC VOID
2137 ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
2139 STRPTR from = bstring;
2140 LONG len =
2141 #if !defined(AROS_FAST_BSTR)
2142 from[0];
2144 if(len > max_len-1)
2145 len =
2146 #endif
2147 max_len-1;
2149 if(len > 0)
2150 memcpy(cstring,from+1,len);
2152 cstring[len] = '\0';
2155 /* Convert a NUL terminated 'C' string into a BCPL string. */
2156 INLINE STATIC VOID
2157 ConvertCString(APTR bstring,LONG max_len,STRPTR cstring,LONG len)
2159 STRPTR to = bstring;
2161 if(len > max_len-1)
2162 len = max_len-1;
2164 #if !defined(AROS_FAST_BSTR)
2165 (*to++) = len;
2166 #endif
2167 memcpy(to,cstring,len);
2168 #if defined(AROS_FAST_BSTR)
2169 to[len] = '\0';
2170 #endif
2173 /****************************************************************************/
2175 /* Build the fully qualified name of a file or directory in reference
2176 * to the name of the parent directory. This takes care of all the
2177 * special cases, such as the root directory. The result will be converted
2178 * to be in a form suitable for use with the SMB file sharing service.
2180 STATIC LONG
2181 BuildFullName(
2182 STRPTR parent_name,
2183 STRPTR name,
2184 STRPTR * result_ptr,
2185 LONG * result_size_ptr)
2187 LONG error = OK;
2188 STRPTR buffer;
2189 LONG len,size;
2190 LONG i;
2192 ENTER();
2194 SHOWSTRING(parent_name);
2195 SHOWSTRING(name);
2197 (*result_ptr) = NULL;
2199 /* Throw everything left of the colon away. */
2200 if(name != NULL)
2202 for(i = 0 ; i < (LONG)strlen(name) ; i++)
2204 if(name[i] == ':')
2206 name = &name[i+1];
2207 break;
2212 /* Now, how much room is needed for the complete
2213 * path to fit into a buffer?
2215 len = 2;
2217 if(parent_name != NULL)
2218 len += strlen(parent_name) + 1;
2220 if(name != NULL)
2221 len += strlen(name) + 1;
2223 if(len < SMB_MAXNAMELEN)
2224 len = SMB_MAXNAMELEN;
2226 size = len + 3;
2228 buffer = AllocateMemory(size);
2229 if(buffer == NULL)
2231 error = ERROR_NO_FREE_STORE;
2232 goto out;
2235 /* Start by filling in the path name. */
2236 if(parent_name != NULL)
2238 /* Skip any excess separators. */
2239 while((*parent_name) == SMB_PATH_SEPARATOR)
2240 parent_name++;
2242 buffer[0] = SMB_PATH_SEPARATOR;
2243 strcpy(&buffer[1],parent_name);
2245 else
2247 strcpy(buffer,SMB_ROOT_DIR_NAME);
2250 /* If there's a name to add, do just that. */
2251 if(name != NULL)
2253 LONG segment_start;
2254 LONG segment_len;
2255 LONG buffer_len;
2256 LONG name_len;
2258 buffer_len = strlen(buffer);
2259 name_len = strlen(name);
2261 segment_start = 0;
2263 while(TRUE)
2265 segment_len = 0;
2267 /* Extract the next path name segment. */
2268 for(i = segment_start ; i <= name_len ; i++)
2270 if(i == name_len)
2272 segment_len = i - segment_start;
2273 break;
2275 else if (name[i] == '/')
2277 segment_len = i - segment_start + 1;
2278 break;
2282 /* We're finished if there are no further
2283 * path name segments to take care of.
2285 if(segment_len == 0)
2287 buffer[buffer_len] = '\0';
2288 break;
2291 /* A single slash indicates that we need to move up
2292 * to the parent directory, if any.
2294 if(segment_len == 1 && name[segment_start] == '/')
2296 /* Is this already the root directory name? */
2297 if(buffer_len <= 1)
2299 FreeMemory(buffer);
2300 buffer = NULL;
2302 goto out;
2304 else
2306 /* Skip the last path component. */
2307 for(i = 1 ; i <= buffer_len ; i++)
2309 if(i == buffer_len)
2311 /* We just skipped the first path
2312 * component following the root
2313 * directory name. We preserve
2314 * the first character since it
2315 * refers to the root directory.
2317 buffer_len = 1;
2318 break;
2320 else if (buffer[buffer_len-i] == SMB_PATH_SEPARATOR)
2322 /* This removes both the path separator and
2323 * the name following it.
2325 buffer_len -= i;
2326 break;
2331 else
2333 /* Add a proper separator character if
2334 * necessary.
2336 if(buffer_len > 0 && buffer[buffer_len-1] != SMB_PATH_SEPARATOR)
2337 buffer[buffer_len++] = SMB_PATH_SEPARATOR;
2339 /* Find out how many characters are in that name; this
2340 * excludes the terminating slash.
2342 if(name[segment_start + segment_len - 1] == '/')
2343 len = segment_len - 1;
2344 else
2345 len = segment_len;
2347 memcpy(&buffer[buffer_len],&name[segment_start],len);
2348 buffer_len += len;
2351 segment_start += segment_len;
2355 (*result_ptr) = buffer;
2356 (*result_size_ptr) = size;
2358 SHOWSTRING(buffer);
2360 out:
2362 if(error != OK)
2363 FreeMemory(buffer);
2365 RETURN(error);
2366 return(error);
2369 /****************************************************************************/
2371 STATIC BOOL
2372 Action_Startup(
2373 struct FileSysStartupMsg * fssm,
2374 struct DosList * device_node,
2375 SIPTR * error_ptr)
2377 LONG cache_size = 0;
2378 LONG max_transmit = -1;
2379 char env_workgroup_name[17];
2380 char env_user_name[64];
2381 char env_password[64];
2383 UBYTE *control;
2384 char env_service_name[17];
2386 BOOL result = DOSTRUE;
2387 LONG error = 0;
2389 ENTER();
2391 DeviceNode = device_node;
2392 device_node->dol_Task = FileSystemPort;
2394 memset(&args,0,sizeof(args));
2396 Parameters = AllocDosObject(DOS_RDARGS, NULL);
2397 if(Parameters == NULL)
2398 goto out;
2399 control = (UBYTE *)
2400 ((struct DosEnvec *)BADDR(fssm->fssm_Environ))->de_Control;
2401 Parameters->RDA_Source.CS_Buffer = control;
2402 Parameters->RDA_Source.CS_Length = strlen(control);
2403 Parameters = ReadArgs(cmd_template,(IPTR *)&args,Parameters);
2404 if(Parameters == NULL)
2406 goto out;
2409 if(args.Workgroup == NULL)
2411 if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
2412 GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
2414 args.Workgroup = env_workgroup_name;
2416 else
2418 args.Workgroup = "WORKGROUP";
2422 if(args.UserName == NULL)
2424 if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
2425 GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
2427 args.UserName = env_user_name;
2431 if(args.Password == NULL)
2433 if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
2434 args.Password = env_password;
2437 if(args.Service == NULL)
2439 if(GetVar("smbfs_service",env_service_name,sizeof(env_service_name),0) > 0 ||
2440 GetVar("smbfs_share",env_service_name,sizeof(env_service_name),0) > 0)
2442 args.Service = env_service_name;
2444 else
2446 ReportError("Required 'SERVICE' parameter was not provided.");
2447 goto out;
2451 if(args.CacheSize != NULL)
2452 cache_size = (*args.CacheSize);
2454 if(args.MaxTransmit != NULL)
2455 max_transmit = (*args.MaxTransmit);
2457 /* Use the default if no user name is given. */
2458 if(args.UserName == NULL)
2459 args.UserName = "GUEST";
2461 /* Volume name defaults to share name. */
2462 if(args.VolumeName == NULL)
2463 args.VolumeName = FilePart(args.Service);
2465 /* Use the default if no device or volume name is given. */
2466 if(args.DeviceName == NULL && args.VolumeName == NULL)
2467 args.DeviceName = "SMBFS";
2469 /* UTF8 file name translation disables code-page based translation. */
2470 if(args.UTF8)
2471 args.TranslationFile = NULL;
2473 CaseSensitive = (BOOL)args.CaseSensitive;
2474 OmitHidden = (BOOL)args.OmitHidden;
2475 TranslateUTF8 = (BOOL)args.UTF8;
2477 /* Configure the debugging options. */
2478 if(args.DebugLevel != NULL)
2479 SETDEBUGLEVEL(*args.DebugLevel);
2480 else
2481 SETDEBUGLEVEL(0);
2483 /* Enable SMB packet decoding, but only if not started from Workbench. */
2484 #if defined(DUMP_SMB)
2486 if(args.DumpSMB)
2487 control_smb_dump(TRUE);
2489 #endif /* DUMP_SMB */
2491 D(("%s (%s)",VERS,DATE));
2493 if(Setup(
2494 args.Password,
2495 args.ChangeCase,
2496 args.TimeZoneOffset,
2497 args.DSTOffset,
2498 args.TranslationFile))
2500 AddVolume(
2501 args.DeviceName,
2502 args.VolumeName,
2503 args.Service,
2504 args.Workgroup,
2505 args.UserName,
2506 args.Password,
2507 args.ClientName,
2508 args.ServerName,
2509 cache_size,
2510 max_transmit,
2511 !args.NetBIOSTransport /* Use raw SMB transport instead of NetBIOS transport? */
2514 else
2516 result = FALSE;
2519 out:
2521 (*error_ptr) = error;
2523 RETURN(result);
2524 return(result);
2527 /****************************************************************************/
2529 STATIC BPTR
2530 Action_Parent(
2531 struct FileLock * parent,
2532 SIPTR * error_ptr)
2534 BPTR result = ZERO;
2535 STRPTR full_name = NULL;
2536 LONG full_name_size;
2537 STRPTR parent_name;
2538 BOOL cleanup = TRUE;
2539 struct LockNode * ln = NULL;
2540 LONG error;
2542 ENTER();
2544 SHOWVALUE(parent);
2546 if(parent != NULL)
2548 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2550 parent_name = parent_ln->ln_FullName;
2552 else
2554 parent_name = NULL;
2557 error = BuildFullName(parent_name,"/",&full_name,&full_name_size);
2558 if(error != OK)
2559 goto out;
2561 /* Check if we ended up having to return the parent of
2562 * the root directory. This is indicated by a NULL
2563 * name pointer and a zero error code.
2565 if(full_name == NULL)
2566 goto out;
2568 ln = AllocateMemory(sizeof(*ln));
2569 if(ln == NULL)
2571 error = ERROR_NO_FREE_STORE;
2572 goto out;
2575 memset(ln,0,sizeof(*ln));
2577 ln->ln_FileLock.fl_Key = (IPTR)ln;
2578 ln->ln_FileLock.fl_Access = SHARED_LOCK;
2579 ln->ln_FileLock.fl_Task = FileSystemPort;
2580 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
2581 ln->ln_FullName = full_name;
2583 SHOWSTRING(full_name);
2585 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2586 if(error < 0)
2588 error = MapErrnoToIoErr(error);
2589 goto out;
2592 AddTail((struct List *)&LockList,(struct Node *)ln);
2593 result = MKBADDR(&ln->ln_FileLock);
2594 cleanup = FALSE;
2595 SHOWVALUE(&ln->ln_FileLock);
2597 out:
2599 if(cleanup)
2601 FreeMemory(full_name);
2602 FreeMemory(ln);
2605 (*error_ptr) = error;
2607 RETURN(result);
2608 return(result);
2611 /****************************************************************************/
2613 /* Find the lock node corresponding to a given name,
2614 * starting from node start. (if node, this one is skipped)
2616 STATIC struct LockNode *
2617 FindNextLockNode(STRPTR name,struct LockNode * last_ln)
2619 struct LockNode * result = NULL;
2620 struct LockNode * ln;
2621 struct LockNode * start;
2623 if(last_ln != NULL)
2624 start = (struct LockNode *)last_ln->ln_MinNode.mln_Succ;
2625 else
2626 start = (struct LockNode *)LockList.mlh_Head;
2628 for(ln = start ;
2629 ln->ln_MinNode.mln_Succ != NULL ;
2630 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
2632 if(CompareNames(name,ln->ln_FullName) == SAME)
2634 result = ln;
2635 break;
2639 return(result);
2642 /****************************************************************************/
2644 STATIC LONG
2645 Action_DeleteObject(
2646 struct FileLock * parent,
2647 APTR bcpl_name,
2648 SIPTR * error_ptr)
2650 LONG result = DOSFALSE;
2651 STRPTR full_name = NULL;
2652 LONG full_name_size;
2653 smba_file_t * file = NULL;
2654 STRPTR parent_name;
2655 STRPTR full_parent_name = NULL;
2656 UBYTE name[MAX_FILENAME_LEN];
2657 struct LockNode * ln;
2658 smba_stat_t st;
2659 LONG error;
2661 ENTER();
2663 if(WriteProtected)
2665 error = ERROR_DISK_WRITE_PROTECTED;
2666 goto out;
2669 SHOWVALUE(parent);
2671 if(parent != NULL)
2673 ln = (struct LockNode *)parent->fl_Key;
2675 parent_name = ln->ln_FullName;
2677 else
2679 parent_name = NULL;
2682 /* Name string, as given in the DOS packet, is in
2683 * BCPL format and needs to be converted into
2684 * 'C' format.
2686 ConvertBString(sizeof(name),name,bcpl_name);
2688 /* Translate the Amiga file name into UTF-8 encoded form? */
2689 if (TranslateUTF8)
2691 UBYTE encoded_name[MAX_FILENAME_LEN];
2692 int encoded_name_len;
2693 LONG name_len = strlen(name);
2695 /* Figure out how long the UTF-8 version will become. */
2696 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
2698 /* Encoding error occured, or the resulting name is longer than the buffer will hold? */
2699 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
2701 error = ERROR_INVALID_COMPONENT_NAME;
2702 goto out;
2705 /* Repeat the encoding process, writing the result to the
2706 * replacement name buffer now.
2708 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
2710 /* Copy it back to the conversion buffer (which is not terribly efficient, though). */
2711 strlcpy(name,encoded_name,sizeof(name));
2713 /* Translate the Amiga file name using a translation table? */
2714 else if (TranslateNames)
2716 TranslateCName(name,A2M);
2719 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2720 if(error != OK)
2721 goto out;
2723 /* Trying to delete the root directory, are you kidding? */
2724 if(full_name == NULL)
2726 error = ERROR_OBJECT_WRONG_TYPE;
2727 goto out;
2730 /* We need to find this file's parent directory, so that
2731 * in case the directory contents are currently being
2732 * examined, that process is restarted.
2734 full_parent_name = AllocateMemory(strlen(full_name)+3);
2735 if(full_parent_name == NULL)
2737 error = ERROR_NO_FREE_STORE;
2738 goto out;
2741 strcpy(full_parent_name,full_name);
2743 /* Build the parent object name - Piru */
2744 if (full_parent_name[0] != '\0')
2746 int i;
2748 i = strlen(full_parent_name) - 1;
2749 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2750 i--;
2752 for ( ; i >= 0 ; i--)
2754 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2756 full_parent_name[i] = '\0';
2757 break;
2762 /* NOTE: Mark all locks to this object as restart, not just first
2763 one - Piru */
2764 ln = NULL;
2765 while ((ln = FindNextLockNode(full_parent_name, ln)) != NULL)
2766 ln->ln_RestartExamine = TRUE;
2768 ln = FindLockNode(full_parent_name,NULL);
2769 if(ln != NULL)
2770 ln->ln_RestartExamine = TRUE;
2772 FreeMemory(full_parent_name);
2773 full_parent_name = NULL;
2775 SHOWSTRING(full_name);
2777 error = smba_open(ServerData,full_name,full_name_size,&file);
2778 if(error < 0)
2780 error = MapErrnoToIoErr(error);
2781 goto out;
2784 error = smba_getattr(file,&st);
2785 if(error < 0)
2787 error = MapErrnoToIoErr(error);
2788 goto out;
2791 smba_close(file);
2792 file = NULL;
2794 if(st.is_dir)
2796 SHOWMSG("removing a directory");
2798 error = smba_rmdir(ServerData,full_name);
2799 if(error < 0)
2801 SHOWVALUE(error);
2803 /* This is a little bit difficult to justify since
2804 * the error code may indicate a different cause,
2805 * but in practice 'EACCES' seems to be returned
2806 * if the directory to remove is not empty.
2808 if(error == (-EACCES))
2809 error = ERROR_DIRECTORY_NOT_EMPTY;
2810 else
2811 error = MapErrnoToIoErr(error);
2813 goto out;
2816 else
2818 SHOWMSG("removing a file");
2820 error = smba_remove(ServerData,full_name);
2821 if(error < 0)
2823 SHOWVALUE(error);
2825 error = MapErrnoToIoErr(error);
2826 goto out;
2830 SHOWMSG("done.");
2832 result = DOSTRUE;
2834 out:
2836 FreeMemory(full_name);
2837 FreeMemory(full_parent_name);
2839 if(file != NULL)
2840 smba_close(file);
2842 (*error_ptr) = error;
2844 RETURN(result);
2845 return(result);
2848 /****************************************************************************/
2850 STATIC BPTR
2851 Action_CreateDir(
2852 struct FileLock * parent,
2853 APTR bcpl_name,
2854 SIPTR * error_ptr)
2856 BPTR result = ZERO;
2857 STRPTR full_name = NULL;
2858 LONG full_name_size;
2859 struct LockNode * ln = NULL;
2860 STRPTR parent_name;
2861 STRPTR dir_name = NULL;
2862 smba_file_t * dir = NULL;
2863 STRPTR base_name;
2864 UBYTE name[MAX_FILENAME_LEN];
2865 LONG error;
2866 LONG i;
2868 ENTER();
2870 if(WriteProtected)
2872 error = ERROR_DISK_WRITE_PROTECTED;
2873 goto out;
2876 SHOWVALUE(parent);
2878 if(parent != NULL)
2880 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2882 parent_name = parent_ln->ln_FullName;
2884 else
2886 parent_name = NULL;
2889 ConvertBString(sizeof(name),name,bcpl_name);
2891 if (TranslateUTF8)
2893 UBYTE encoded_name[MAX_FILENAME_LEN];
2894 int encoded_name_len;
2895 LONG name_len = strlen(name);
2897 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
2898 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
2900 error = ERROR_INVALID_COMPONENT_NAME;
2901 goto out;
2904 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
2906 strlcpy(name,encoded_name,sizeof(name));
2908 else if (TranslateNames)
2910 TranslateCName(name,A2M);
2913 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2914 if(error != OK)
2915 goto out;
2917 /* Trying to overwrite the root directory, are you kidding? */
2918 if(full_name == NULL)
2920 error = ERROR_OBJECT_IN_USE;
2921 goto out;
2924 dir_name = AllocateMemory(strlen(full_name)+3);
2925 if(dir_name == NULL)
2927 error = ERROR_NO_FREE_STORE;
2928 goto out;
2931 strcpy(dir_name,full_name);
2932 base_name = NULL;
2933 for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
2935 if(dir_name[i] == SMB_PATH_SEPARATOR)
2937 if(i == 0)
2939 memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1);
2940 i++;
2943 dir_name[i] = '\0';
2945 base_name = &dir_name[i+1];
2946 break;
2950 ln = AllocateMemory(sizeof(*ln));
2951 if(ln == NULL)
2953 error = ERROR_NO_FREE_STORE;
2954 goto out;
2957 memset(ln,0,sizeof(*ln));
2959 ln->ln_FileLock.fl_Key = (IPTR)ln;
2960 ln->ln_FileLock.fl_Access = EXCLUSIVE_LOCK;
2961 ln->ln_FileLock.fl_Task = FileSystemPort;
2962 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
2963 ln->ln_FullName = full_name;
2965 error = smba_open(ServerData,dir_name,strlen(full_name)+3,&dir);
2966 if(error < 0)
2968 error = MapErrnoToIoErr(error);
2969 goto out;
2972 error = smba_mkdir(dir,base_name);
2973 if(error < 0)
2975 error = MapErrnoToIoErr(error);
2976 goto out;
2979 smba_close(dir);
2980 dir = NULL;
2982 SHOWSTRING(full_name);
2984 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2985 if(error < 0)
2987 error = MapErrnoToIoErr(error);
2988 goto out;
2991 AddTail((struct List *)&LockList,(struct Node *)ln);
2992 result = MKBADDR(&ln->ln_FileLock);
2993 SHOWVALUE(&ln->ln_FileLock);
2995 out:
2997 if(dir != NULL)
2998 smba_close(dir);
3000 FreeMemory(dir_name);
3002 if(result == ZERO)
3004 FreeMemory(full_name);
3005 FreeMemory(ln);
3008 (*error_ptr) = error;
3010 RETURN(result);
3011 return(result);
3014 /****************************************************************************/
3016 STATIC BPTR
3017 Action_LocateObject(
3018 struct FileLock * parent,
3019 APTR bcpl_name,
3020 LONG mode,
3021 SIPTR * error_ptr)
3023 BPTR result = ZERO;
3024 STRPTR full_name = NULL;
3025 LONG full_name_size;
3026 struct LockNode * ln = NULL;
3027 STRPTR parent_name;
3028 UBYTE name[MAX_FILENAME_LEN];
3029 LONG error;
3031 ENTER();
3033 SHOWVALUE(parent);
3035 if(parent != NULL)
3037 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
3039 parent_name = parent_ln->ln_FullName;
3041 else
3043 parent_name = NULL;
3046 ConvertBString(sizeof(name),name,bcpl_name);
3048 if (TranslateUTF8)
3050 UBYTE encoded_name[MAX_FILENAME_LEN];
3051 int encoded_name_len;
3052 LONG name_len = strlen(name);
3054 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3055 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3057 error = ERROR_INVALID_COMPONENT_NAME;
3058 goto out;
3061 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3063 strlcpy(name,encoded_name,sizeof(name));
3065 else if (TranslateNames)
3067 TranslateCName(name,A2M);
3070 if(IsReservedName(FilePart(name)))
3072 error = ERROR_OBJECT_NOT_FOUND;
3073 goto out;
3076 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3077 if(error != OK)
3078 goto out;
3080 /* Trying to get a lock on the root directory's parent?
3081 * My pleasure.
3083 if(full_name == NULL)
3084 goto out;
3086 ln = AllocateMemory(sizeof(*ln));
3087 if(ln == NULL)
3089 error = ERROR_NO_FREE_STORE;
3090 goto out;
3093 memset(ln,0,sizeof(*ln));
3095 ln->ln_FileLock.fl_Key = (IPTR)ln;
3096 ln->ln_FileLock.fl_Access = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK;
3097 ln->ln_FileLock.fl_Task = FileSystemPort;
3098 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3099 ln->ln_FullName = full_name;
3101 error = CheckAccessModeCollision(full_name,ln->ln_FileLock.fl_Access);
3102 if(error != OK)
3103 goto out;
3105 SHOWSTRING(full_name);
3107 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3108 if(error < 0)
3110 error = MapErrnoToIoErr(error);
3111 goto out;
3114 AddTail((struct List *)&LockList,(struct Node *)ln);
3115 result = MKBADDR(&ln->ln_FileLock);
3116 SHOWVALUE(&ln->ln_FileLock);
3118 out:
3120 if(result == ZERO)
3122 FreeMemory(full_name);
3123 FreeMemory(ln);
3126 (*error_ptr) = error;
3128 RETURN(result);
3129 return(result);
3132 /****************************************************************************/
3134 STATIC BPTR
3135 Action_CopyDir(
3136 struct FileLock * lock,
3137 SIPTR * error_ptr)
3139 BPTR result = ZERO;
3140 STRPTR full_name = NULL;
3141 LONG full_name_size;
3142 struct LockNode * ln = NULL;
3143 STRPTR source_name;
3144 LONG source_mode;
3145 LONG error;
3147 ENTER();
3149 SHOWVALUE(lock);
3151 if(lock != NULL && lock->fl_Access != SHARED_LOCK)
3153 SHOWMSG("cannot duplicate exclusive lock");
3154 error = ERROR_OBJECT_IN_USE;
3155 goto out;
3158 ln = AllocateMemory(sizeof(*ln));
3159 if(ln == NULL)
3161 error = ERROR_NO_FREE_STORE;
3162 goto out;
3165 memset(ln,0,sizeof(*ln));
3167 if(lock != NULL)
3169 struct LockNode * source = (struct LockNode *)lock->fl_Key;
3171 source_name = source->ln_FullName;
3172 source_mode = source->ln_FileLock.fl_Access;
3174 else
3176 source_name = SMB_ROOT_DIR_NAME;
3177 source_mode = SHARED_LOCK;
3180 full_name_size = strlen(source_name)+3;
3181 if(full_name_size < SMB_MAXNAMELEN+1)
3182 full_name_size = SMB_MAXNAMELEN+1;
3184 full_name = AllocateMemory(full_name_size);
3185 if(full_name == NULL)
3187 error = ERROR_NO_FREE_STORE;
3188 goto out;
3191 strcpy(full_name,source_name);
3193 ln->ln_FileLock.fl_Key = (IPTR)ln;
3194 ln->ln_FileLock.fl_Access = source_mode;
3195 ln->ln_FileLock.fl_Task = FileSystemPort;
3196 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3197 ln->ln_FullName = full_name;
3199 SHOWSTRING(full_name);
3201 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3202 if(error < 0)
3204 error = MapErrnoToIoErr(error);
3205 goto out;
3208 AddTail((struct List *)&LockList,(struct Node *)ln);
3209 result = MKBADDR(&ln->ln_FileLock);
3210 SHOWVALUE(&ln->ln_FileLock);
3212 out:
3214 if(result == ZERO)
3216 FreeMemory(full_name);
3217 FreeMemory(ln);
3220 (*error_ptr) = error;
3222 RETURN(result);
3223 return(result);
3226 /****************************************************************************/
3228 STATIC LONG
3229 Action_FreeLock(
3230 struct FileLock * lock,
3231 SIPTR * error_ptr)
3233 LONG result = DOSTRUE;
3234 struct LockNode * ln;
3235 LONG error = OK;
3237 ENTER();
3239 SHOWVALUE(lock);
3241 if(lock == NULL)
3242 goto out;
3244 ln = (struct LockNode *)lock->fl_Key;
3246 Remove((struct Node *)ln);
3248 smba_close(ln->ln_File);
3249 FreeMemory(ln->ln_FullName);
3250 FreeMemory(ln);
3252 out:
3254 (*error_ptr) = error;
3256 RETURN(result);
3257 return(result);
3260 /****************************************************************************/
3262 STATIC LONG
3263 Action_SameLock(
3264 struct FileLock * lock1,
3265 struct FileLock * lock2,
3266 SIPTR * error_ptr)
3268 LONG result = DOSFALSE;
3269 STRPTR name1;
3270 STRPTR name2;
3271 LONG error = OK;
3273 ENTER();
3275 SHOWVALUE(lock1);
3276 SHOWVALUE(lock2);
3278 if(lock1 != NULL)
3280 struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
3282 name1 = ln->ln_FullName;
3284 else
3286 name1 = SMB_ROOT_DIR_NAME;
3289 if(lock2 != NULL)
3291 struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
3293 name2 = ln->ln_FullName;
3295 else
3297 name2 = SMB_ROOT_DIR_NAME;
3300 SHOWSTRING(name1);
3301 SHOWSTRING(name2);
3303 if(Stricmp(name1,name2) == SAME)
3304 result = DOSTRUE;
3306 (*error_ptr) = error;
3308 RETURN(result);
3309 return(result);
3312 /****************************************************************************/
3314 STATIC LONG
3315 Action_SetProtect(
3316 struct FileLock * parent,
3317 APTR bcpl_name,
3318 LONG mask,
3319 SIPTR * error_ptr)
3321 LONG result = DOSFALSE;
3322 STRPTR full_name = NULL;
3323 LONG full_name_size;
3324 smba_file_t * file = NULL;
3325 STRPTR parent_name;
3326 UBYTE name[MAX_FILENAME_LEN];
3327 smba_stat_t st;
3328 LONG error;
3330 ENTER();
3332 if(WriteProtected)
3334 error = ERROR_DISK_WRITE_PROTECTED;
3335 goto out;
3338 SHOWVALUE(parent);
3340 if(parent != NULL)
3342 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
3344 parent_name = ln->ln_FullName;
3346 else
3348 parent_name = NULL;
3351 ConvertBString(sizeof(name),name,bcpl_name);
3353 if (TranslateUTF8)
3355 UBYTE encoded_name[MAX_FILENAME_LEN];
3356 int encoded_name_len;
3357 LONG name_len = strlen(name);
3359 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3360 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3362 error = ERROR_INVALID_COMPONENT_NAME;
3363 goto out;
3366 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3368 strlcpy(name,encoded_name,sizeof(name));
3370 else if (TranslateNames)
3372 TranslateCName(name,A2M);
3375 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3376 if(error != OK)
3377 goto out;
3379 /* Trying to change the protection bits of the root
3380 * directory, are you kidding?
3382 if(full_name == NULL)
3384 error = ERROR_OBJECT_WRONG_TYPE;
3385 goto out;
3388 SHOWSTRING(full_name);
3390 error = smba_open(ServerData,full_name,full_name_size,&file);
3391 if(error < 0)
3393 error = MapErrnoToIoErr(error);
3394 goto out;
3397 memset(&st,0,sizeof(st));
3399 mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
3401 st.atime = -1;
3402 st.ctime = -1;
3403 st.mtime = -1;
3404 st.size = -1;
3406 if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
3408 SHOWMSG("write protection enabled");
3409 st.is_wp = TRUE;
3411 else
3413 SHOWMSG("write protection disabled");
3416 /* Careful: the 'archive' attribute has exactly the opposite
3417 * meaning in the Amiga and the SMB worlds.
3419 st.is_archive = ((mask & FIBF_ARCHIVE) == 0);
3421 /* The 'system' attribute is associated with the 'pure' bit for now. */
3422 st.is_system = ((mask & FIBF_PURE) != 0);
3424 error = smba_setattr(file,&st);
3425 if(error < 0)
3427 error = MapErrnoToIoErr(error);
3428 goto out;
3431 result = DOSTRUE;
3433 out:
3435 FreeMemory(full_name);
3437 if(file != NULL)
3438 smba_close(file);
3440 (*error_ptr) = error;
3442 RETURN(result);
3443 return(result);
3446 /****************************************************************************/
3448 STATIC LONG
3449 Action_RenameObject(
3450 struct FileLock * source_lock,
3451 APTR source_bcpl_name,
3452 struct FileLock * destination_lock,
3453 APTR destination_bcpl_name,
3454 SIPTR * error_ptr)
3456 struct LockNode * ln;
3457 LONG result = DOSFALSE;
3458 STRPTR full_source_name = NULL;
3459 LONG full_source_name_size;
3460 STRPTR full_destination_name = NULL;
3461 LONG full_destination_name_size;
3462 UBYTE name[MAX_FILENAME_LEN];
3463 STRPTR parent_name;
3464 LONG error;
3466 ENTER();
3468 if(WriteProtected)
3470 error = ERROR_DISK_WRITE_PROTECTED;
3471 goto out;
3474 SHOWVALUE(source_lock);
3475 SHOWVALUE(destination_lock);
3477 if(source_lock != NULL)
3479 ln = (struct LockNode *)source_lock->fl_Key;
3481 parent_name = ln->ln_FullName;
3483 else
3485 parent_name = NULL;
3488 ConvertBString(sizeof(name),name,source_bcpl_name);
3490 if (TranslateUTF8)
3492 UBYTE encoded_name[MAX_FILENAME_LEN];
3493 int encoded_name_len;
3494 LONG name_len = strlen(name);
3496 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3497 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3499 error = ERROR_INVALID_COMPONENT_NAME;
3500 goto out;
3503 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3505 strlcpy(name,encoded_name,sizeof(name));
3507 else if (TranslateNames)
3509 TranslateCName(name,A2M);
3512 error = BuildFullName(parent_name,name,&full_source_name,&full_source_name_size);
3513 if(error != OK)
3514 goto out;
3516 /* Trying to rename the root directory, are you kidding? */
3517 if(full_source_name == NULL)
3519 error = ERROR_OBJECT_IN_USE;
3520 goto out;
3523 if(destination_lock != NULL)
3525 ln = (struct LockNode *)destination_lock->fl_Key;
3527 parent_name = ln->ln_FullName;
3529 else
3531 parent_name = NULL;
3534 ConvertBString(sizeof(name),name,destination_bcpl_name);
3536 if (TranslateUTF8)
3538 UBYTE encoded_name[MAX_FILENAME_LEN];
3539 int encoded_name_len;
3540 LONG name_len = strlen(name);
3542 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3543 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3545 error = ERROR_INVALID_COMPONENT_NAME;
3546 goto out;
3549 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3551 strlcpy(name,encoded_name,sizeof(name));
3553 else if (TranslateNames)
3555 TranslateCName(name,A2M);
3558 error = BuildFullName(parent_name,name,&full_destination_name,&full_destination_name_size);
3559 if(error != OK)
3560 goto out;
3562 /* Trying to rename the root directory, are you kidding? */
3563 if(full_destination_name == NULL)
3565 error = ERROR_OBJECT_IN_USE;
3566 goto out;
3569 error = NameAlreadyInUse(full_source_name);
3570 if(error != OK)
3571 goto out;
3573 error = NameAlreadyInUse(full_destination_name);
3574 if(error != OK)
3575 goto out;
3577 SHOWSTRING(full_source_name);
3578 SHOWSTRING(full_destination_name);
3580 error = smba_rename(ServerData,full_source_name,full_destination_name);
3581 if(error < 0)
3583 error = MapErrnoToIoErr(error);
3584 goto out;
3587 result = DOSTRUE;
3589 out:
3591 FreeMemory(full_source_name);
3592 FreeMemory(full_destination_name);
3594 (*error_ptr) = error;
3596 RETURN(result);
3597 return(result);
3600 /****************************************************************************/
3602 STATIC LONG
3603 Action_DiskInfo(
3604 struct InfoData * id,
3605 SIPTR * error_ptr)
3607 LONG result = DOSTRUE;
3608 long block_size;
3609 long num_blocks;
3610 long num_blocks_free;
3611 LONG error;
3613 ENTER();
3615 memset(id,0,sizeof(*id));
3617 if(WriteProtected)
3618 id->id_DiskState = ID_WRITE_PROTECTED;
3619 else
3620 id->id_DiskState = ID_VALIDATED;
3622 error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
3623 if(error >= 0)
3625 SHOWMSG("got the disk data");
3626 SHOWVALUE(block_size);
3627 SHOWVALUE(num_blocks);
3628 SHOWVALUE(num_blocks_free);
3630 if(block_size <= 0)
3631 block_size = 512;
3633 if(block_size < 512)
3635 num_blocks /= (512 / block_size);
3636 num_blocks_free /= (512 / block_size);
3638 else if (block_size > 512)
3640 num_blocks *= (block_size / 512);
3641 num_blocks_free *= (block_size / 512);
3644 id->id_NumBlocks = num_blocks;
3645 id->id_NumBlocksUsed = num_blocks - num_blocks_free;
3646 id->id_BytesPerBlock = 512;
3647 id->id_DiskType = ID_DOS_DISK;
3648 id->id_VolumeNode = MKBADDR(VolumeNode);
3649 id->id_InUse = NOT (IsListEmpty(&FileList) && IsListEmpty(&LockList));
3651 if(id->id_NumBlocks == 0)
3652 id->id_NumBlocks = 1;
3654 if(id->id_NumBlocksUsed == 0)
3655 id->id_NumBlocksUsed = 1;
3657 else
3659 SHOWMSG("could not get any disk data");
3661 id->id_NumBlocks = 1;
3662 id->id_NumBlocksUsed = 1;
3663 id->id_BytesPerBlock = 512;
3664 id->id_DiskType = ID_NO_DISK_PRESENT;
3666 error = MapErrnoToIoErr(error);
3667 result = DOSFALSE;
3670 SHOWVALUE(id->id_NumBlocks);
3671 SHOWVALUE(id->id_NumBlocksUsed);
3672 SHOWVALUE(id->id_BytesPerBlock);
3673 SHOWVALUE(id->id_DiskType);
3674 SHOWVALUE(id->id_VolumeNode);
3675 SHOWVALUE(id->id_InUse);
3677 (*error_ptr) = error;
3679 RETURN(result);
3680 return(result);
3683 STATIC LONG
3684 Action_Info(
3685 struct FileLock * lock,
3686 struct InfoData * id,
3687 SIPTR * error_ptr)
3689 LONG result;
3691 ENTER();
3693 SHOWVALUE(lock);
3695 /* We need to check if the lock matches the volume node. However,
3696 * a NULL lock is valid, too.
3698 if(lock != NULL && lock->fl_Volume != MKBADDR(VolumeNode))
3700 SHOWMSG("volume node does not match");
3702 result = DOSFALSE;
3704 (*error_ptr) = ERROR_NO_DISK;
3706 else
3708 result = Action_DiskInfo(id,error_ptr);
3711 RETURN(result);
3712 return(result);
3715 /****************************************************************************/
3717 STATIC LONG
3718 Action_ExamineObject(
3719 struct FileLock * lock,
3720 struct FileInfoBlock * fib,
3721 SIPTR * error_ptr)
3723 LONG result = DOSFALSE;
3724 LONG error = OK;
3726 ENTER();
3728 SHOWVALUE(lock);
3730 memset(fib,0,sizeof(*fib));
3732 if(lock == NULL)
3734 #if !defined(__AROS__)
3735 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3736 LONG len = volume_name[0];
3738 memcpy(fib->fib_FileName+1,volume_name+1,len);
3739 fib->fib_FileName[0] = len;
3740 #else
3741 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3742 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3744 memcpy(fib->fib_FileName + 1, volume_name, len);
3745 fib->fib_FileName[0] = len;
3746 #endif
3747 SHOWMSG("ZERO root lock");
3749 fib->fib_DirEntryType = ST_ROOT;
3750 fib->fib_EntryType = ST_ROOT;
3751 fib->fib_NumBlocks = 1;
3752 fib->fib_Date = VolumeNode->dol_misc.dol_volume.dol_VolumeDate;
3753 fib->fib_DiskKey = -1;
3754 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3755 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3757 else
3759 struct LockNode * ln = (struct LockNode *)lock->fl_Key;
3760 LONG seconds;
3761 smba_stat_t st;
3763 error = smba_getattr(ln->ln_File,&st);
3764 if(error < 0)
3766 SHOWMSG("information not available");
3768 error = MapErrnoToIoErr(error);
3769 goto out;
3772 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3773 if(seconds < 0)
3774 seconds = 0;
3776 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
3777 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
3778 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
3780 SHOWSTRING(ln->ln_FullName);
3782 if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME)
3784 #if !defined(__AROS__)
3785 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3786 LONG len = volume_name[0];
3788 memcpy(fib->fib_FileName+1,volume_name+1,len);
3789 fib->fib_FileName[0] = len;
3790 #else
3791 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3792 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3794 memcpy(fib->fib_FileName + 1, volume_name, len);
3795 fib->fib_FileName[0] = len;
3796 #endif
3797 SHOWMSG("root lock");
3799 fib->fib_DirEntryType = ST_ROOT;
3800 fib->fib_EntryType = ST_ROOT;
3801 fib->fib_NumBlocks = 1;
3802 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3803 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3805 else
3807 STRPTR name;
3808 LONG name_len;
3809 LONG i;
3811 name = ln->ln_FullName;
3812 name_len = strlen(name);
3814 for(i = name_len-1 ; i >= 0 ; i--)
3816 if(name[i] == SMB_PATH_SEPARATOR)
3818 name = &name[i+1];
3819 break;
3823 /* Just checking: will the name fit? */
3824 if(name_len >= sizeof(fib->fib_FileName))
3826 error = ERROR_INVALID_COMPONENT_NAME;
3827 goto out;
3830 /* Translate the name of the file/directory from UTF-8
3831 * into AmigaOS ISO 8859-1 (ISO Latin 1) encoding?
3833 if(TranslateUTF8)
3835 UBYTE decoded_name[MAX_FILENAME_LEN];
3836 int decoded_name_len;
3838 /* Try to decode the file file, translating it into ISO 8859-1 format. */
3839 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
3841 /* Decoding error occured, or the decoded name would be longer than
3842 * buffer would allow?
3844 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
3846 error = ERROR_INVALID_COMPONENT_NAME;
3847 goto out;
3850 /* Decode the name for real. */
3851 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
3853 /* Store the decoded name in the form expected
3854 * by dos.library (which will then translate it again).
3856 fib->fib_FileName[0] = decoded_name_len;
3857 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
3859 else
3861 /* Store the file/directory name in the form expected
3862 * by dos.library.
3864 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
3866 /* If necessary, translate the name to Amiga format using a mapping table. */
3867 if(TranslateNames)
3868 TranslateBName(fib->fib_FileName,M2A);
3871 fib->fib_DirEntryType = st.is_dir ? ST_USERDIR : ST_FILE;
3872 fib->fib_EntryType = fib->fib_DirEntryType;
3873 fib->fib_NumBlocks = (st.size + 511) / 512;
3874 fib->fib_Size = st.size;
3875 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3876 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3878 if(st.is_wp)
3879 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
3881 /* Careful: the 'archive' attribute has exactly the opposite
3882 * meaning in the Amiga and the SMB worlds.
3884 if(NOT st.is_archive)
3885 fib->fib_Protection |= FIBF_ARCHIVE;
3887 if(st.is_system)
3888 fib->fib_Protection |= FIBF_PURE;
3890 if(NOT st.is_dir)
3891 fib->fib_DiskKey = -1;
3895 result = DOSTRUE;
3897 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib->fib_FileName)));
3898 SHOWVALUE(fib->fib_DirEntryType);
3899 SHOWVALUE(fib->fib_NumBlocks);
3900 SHOWVALUE(fib->fib_Size);
3901 SHOWVALUE(fib->fib_Date.ds_Days);
3902 SHOWVALUE(fib->fib_Date.ds_Minute);
3903 SHOWVALUE(fib->fib_Date.ds_Tick);
3904 SHOWVALUE(fib->fib_DiskKey);
3906 out:
3908 (*error_ptr) = error;
3910 RETURN(result);
3911 return(result);
3914 /****************************************************************************/
3916 STATIC BOOL
3917 NameIsAcceptable(STRPTR name,LONG max_len)
3919 BOOL result = FALSE;
3920 UBYTE c;
3922 /* This takes care of "." and "..". */
3923 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
3924 goto out;
3926 /* Now for embedded '/', ':' and '\' characters and
3927 * names that just don't want to fit.
3929 while((c = (*name++)) != '\0')
3931 max_len--;
3932 if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
3933 goto out;
3936 result = TRUE;
3938 out:
3940 return(result);
3943 /****************************************************************************/
3945 static int
3946 dir_scan_callback_func_exnext(
3947 struct FileInfoBlock * fib,
3948 int unused_fpos,
3949 int nextpos,
3950 char * name,
3951 int eof,
3952 smba_stat_t * st)
3954 int result = 0;
3955 LONG name_len;
3956 LONG seconds;
3958 ENTER();
3960 D((" '%s'",name));
3961 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
3962 st->is_dir,st->is_wp,st->is_hidden,st->size));
3963 D((" nextpos=%ld eof=%ld",nextpos,eof));
3965 /* Skip file and drawer names that we wouldn't be
3966 * able to handle in the first place.
3968 if(!NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) || (st->is_hidden && OmitHidden))
3969 goto out;
3971 name_len = strlen(name);
3973 if(TranslateUTF8)
3975 UBYTE decoded_name[MAX_FILENAME_LEN];
3976 int decoded_name_len;
3978 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
3979 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
3980 goto out;
3982 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
3984 fib->fib_FileName[0] = decoded_name_len;
3985 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
3987 else
3989 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
3991 if(TranslateNames)
3992 TranslateBName(fib->fib_FileName,M2A);
3995 fib->fib_DirEntryType = st->is_dir ? ST_USERDIR : ST_FILE;
3996 fib->fib_EntryType = fib->fib_DirEntryType;
3997 fib->fib_NumBlocks = (st->size + 511) / 512;
3998 fib->fib_Size = st->size;
3999 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
4000 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
4002 if(st->is_wp)
4003 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4005 /* Careful: the 'archive' attribute has exactly the opposite
4006 * meaning in the Amiga and the SMB worlds.
4008 if(NOT st->is_archive)
4009 fib->fib_Protection |= FIBF_ARCHIVE;
4011 if(st->is_system)
4012 fib->fib_Protection |= FIBF_PURE;
4014 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4015 seconds = (st->mtime == 0 ? st->ctime : st->mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4016 if(seconds < 0)
4017 seconds = 0;
4019 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
4020 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
4021 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
4023 result = 1;
4025 out:
4027 fib->fib_DiskKey = eof ? -1 : nextpos;
4029 RETURN(result);
4030 return(result);
4033 STATIC LONG
4034 Action_ExamineNext(
4035 struct FileLock * lock,
4036 struct FileInfoBlock * fib,
4037 SIPTR * error_ptr)
4039 struct LockNode * ln;
4040 LONG result = DOSFALSE;
4041 LONG error = OK;
4042 long offset;
4043 int count;
4045 ENTER();
4047 SHOWVALUE(lock);
4049 if(fib->fib_DiskKey == -1)
4051 SHOWMSG("scanning finished.");
4052 error = ERROR_NO_MORE_ENTRIES;
4053 goto out;
4056 if(lock == NULL)
4058 SHOWMSG("invalid lock");
4059 error = ERROR_INVALID_LOCK;
4060 goto out;
4063 offset = fib->fib_DiskKey;
4065 ln = (struct LockNode *)lock->fl_Key;
4067 /* Check if we should restart scanning the directory
4068 * contents. This is tricky at best and may produce
4069 * irritating results :(
4071 if(ln->ln_RestartExamine)
4073 offset = 0;
4075 ln->ln_RestartExamine = FALSE;
4078 memset(fib,0,sizeof(*fib));
4080 SHOWMSG("calling 'smba_readdir'");
4081 SHOWVALUE(offset);
4083 count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
4085 SHOWVALUE(count);
4087 if(count == 0 || fib->fib_FileName[0] == '\0')
4089 SHOWMSG("nothing to be read");
4090 fib->fib_DiskKey = -1;
4092 error = ERROR_NO_MORE_ENTRIES;
4093 goto out;
4095 else if (count == (-EIO))
4097 SHOWMSG("ouch! directory read error");
4098 fib->fib_DiskKey = -1;
4100 error = ERROR_NO_DEFAULT_DIR;
4101 goto out;
4103 else if (count < 0)
4105 SHOWMSG("error whilst scanning");
4106 SHOWVALUE(count);
4107 fib->fib_DiskKey = -1;
4109 error = MapErrnoToIoErr(count);
4110 goto out;
4113 result = DOSTRUE;
4115 out:
4117 (*error_ptr) = error;
4119 RETURN(result);
4120 return(result);
4123 /****************************************************************************/
4125 struct ExAllContext
4127 struct ExAllData * ec_Last;
4128 struct ExAllData * ec_Next;
4129 ULONG ec_BytesLeft;
4130 ULONG ec_MinSize;
4131 struct ExAllControl * ec_Control;
4132 ULONG ec_Type;
4133 LONG ec_Error;
4134 BOOL ec_FirstAttempt;
4137 static int
4138 dir_scan_callback_func_exall(
4139 struct ExAllContext * ec,
4140 int unused_fpos,
4141 int nextpos,
4142 char * name,
4143 int eof,
4144 smba_stat_t * st)
4146 UBYTE decoded_name[MAX_FILENAME_LEN];
4147 BOOL ignore_this_entry = FALSE;
4148 int result = 0;
4150 ENTER();
4152 D((" '%s'",name));
4153 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4154 st->is_dir,st->is_wp,st->is_hidden,st->size));
4155 D((" nextpos=%ld eof=%ld",nextpos,eof));
4157 /* If necessary, translate the name of the file first, so that we
4158 * can decide early on whether or not it should show up in a
4159 * directory listing. This filters out, for example, files using
4160 * characters which are not usable on the Amiga because they fall
4161 * outside the 8 bit character set used.
4163 if(TranslateUTF8)
4165 LONG name_len = strlen(name);
4166 int decoded_name_len;
4168 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
4169 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
4171 ignore_this_entry = TRUE;
4173 else
4175 decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
4177 /* Use the decoded replacement name. */
4178 name = decoded_name;
4182 /* Skip file and drawer names that we wouldn't be
4183 * able to handle in the first place.
4185 if(!ignore_this_entry && NameIsAcceptable((STRPTR)name,MAX_FILENAME_LEN) && NOT (st->is_hidden && OmitHidden))
4187 struct ExAllData * ed;
4188 ULONG size;
4189 ULONG type = ec->ec_Type;
4190 BOOL take_it;
4192 size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3UL;
4193 SHOWVALUE(size);
4194 if(size > ec->ec_BytesLeft)
4196 D(("size %ld > ec->ec_BytesLeft %ld",size,ec->ec_BytesLeft));
4198 /* If this is the first directory entry,
4199 * stop the entire process before it has
4200 * really begun.
4202 if(ec->ec_FirstAttempt)
4204 SHOWMSG("this was the first read attempt.");
4205 ec->ec_Control->eac_Entries = 0;
4206 ec->ec_Error = ERROR_NO_FREE_STORE;
4208 else
4210 SHOWMSG("try again");
4211 ec->ec_Error = 0;
4214 result = 1;
4215 goto out;
4218 ed = ec->ec_Next;
4220 ed->ed_Next = NULL;
4221 ed->ed_Name = (STRPTR)(((IPTR)ed) + ec->ec_MinSize);
4222 strcpy(ed->ed_Name,name);
4224 if(!TranslateUTF8 && TranslateNames)
4225 TranslateCName(ed->ed_Name,M2A);
4227 if(type >= ED_TYPE)
4228 ed->ed_Type = st->is_dir ? ST_USERDIR : ST_FILE;
4230 if(type >= ED_SIZE)
4231 ed->ed_Size = st->size;
4233 if(type >= ED_PROTECTION)
4235 ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
4236 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
4238 if(st->is_wp)
4239 ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4241 /* Careful: the 'archive' attribute has exactly the opposite
4242 * meaning in the Amiga and the SMB worlds.
4244 if(NOT st->is_archive)
4245 ed->ed_Prot |= FIBF_ARCHIVE;
4247 if(st->is_system)
4248 ed->ed_Prot |= FIBF_PURE;
4251 if(type >= ED_DATE)
4253 LONG seconds;
4255 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4256 seconds = (st->mtime == 0 ? st->ctime : st->mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4257 if(seconds < 0)
4258 seconds = 0;
4260 ed->ed_Days = (seconds / (24 * 60 * 60));
4261 ed->ed_Mins = (seconds % (24 * 60 * 60)) / 60;
4262 ed->ed_Ticks = (seconds % 60) * TICKS_PER_SECOND;
4265 if(type >= ED_COMMENT)
4266 ed->ed_Comment = "";
4268 if(type >= ED_OWNER)
4269 ed->ed_OwnerUID = ed->ed_OwnerGID = 0;
4271 take_it = TRUE;
4273 if(ec->ec_Control->eac_MatchString != NULL)
4275 SHOWMSG("checking against match string");
4276 if(NOT MatchPatternNoCase(ec->ec_Control->eac_MatchString,ed->ed_Name))
4278 SHOWMSG("does not match");
4279 take_it = FALSE;
4283 if(take_it && ec->ec_Control->eac_MatchFunc != NULL)
4285 SHOWMSG("calling match func");
4287 /* NOTE: the order of the parameters passed to the match hook
4288 * function can be somewhat confusing. For standard
4289 * hook functions, the order of the parameters and the
4290 * registers they go into is hook=A0, object=A2,
4291 * message=A1. However, the documentation for the 'ExAll()'
4292 * function always lists them in ascending order, that is
4293 * hook=A0, message=A1, object=A2, which can lead to
4294 * quite some confusion and strange errors.
4296 if(NOT CallHookPkt(ec->ec_Control->eac_MatchFunc,&type,ed))
4298 SHOWMSG("does not match");
4299 take_it = FALSE;
4303 if(take_it)
4305 SHOWMSG("registering new entry");
4307 if(ec->ec_Last != NULL)
4308 ec->ec_Last->ed_Next = ed;
4310 ec->ec_Last = ed;
4311 ec->ec_Next = (struct ExAllData *)(((IPTR)ed) + size);
4312 ec->ec_BytesLeft -= size;
4313 ec->ec_Control->eac_Entries++;
4315 SHOWVALUE(ec->ec_Last->ed_Next);
4316 SHOWVALUE(ed->ed_Name);
4317 SHOWVALUE(ed->ed_Comment);
4321 ec->ec_Control->eac_LastKey = (ULONG)(eof ? -1 : nextpos);
4323 out:
4325 ec->ec_FirstAttempt = FALSE;
4327 RETURN(result);
4328 return(result);
4331 STATIC LONG
4332 Action_ExamineAll(
4333 struct FileLock * lock,
4334 struct ExAllData * ed,
4335 ULONG size,
4336 ULONG type,
4337 struct ExAllControl * eac,
4338 SIPTR * error_ptr)
4340 struct ExAllContext ec;
4341 struct LockNode * ln;
4342 LONG result = DOSFALSE;
4343 LONG error = OK;
4344 LONG offset;
4345 int count;
4347 ENTER();
4349 SHOWVALUE(lock);
4351 SHOWVALUE(eac->eac_LastKey);
4353 eac->eac_Entries = 0;
4355 if(size < sizeof(ed->ed_Next))
4357 SHOWMSG("buffer is far too short.");
4358 error = ERROR_NO_FREE_STORE;
4359 goto out;
4362 ed->ed_Next = NULL;
4364 if(eac->eac_LastKey == (ULONG)-1)
4366 SHOWMSG("scanning finished.");
4367 error = ERROR_NO_MORE_ENTRIES;
4368 goto out;
4371 if(lock == NULL)
4373 SHOWMSG("invalid lock");
4374 error = ERROR_INVALID_LOCK;
4375 goto out;
4378 if(type < ED_NAME || type > ED_OWNER)
4380 D(("type %ld not supported",type));
4381 error = ERROR_BAD_NUMBER;
4382 goto out;
4385 SHOWVALUE(type);
4387 memset(&ec,0,sizeof(ec));
4389 ec.ec_Next = ed;
4390 ec.ec_BytesLeft = size;
4391 ec.ec_Control = eac;
4392 ec.ec_Type = type;
4393 ec.ec_Error = ERROR_NO_MORE_ENTRIES;
4394 ec.ec_FirstAttempt = TRUE;
4396 switch(type)
4398 case ED_NAME:
4400 ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
4401 break;
4403 case ED_TYPE:
4405 ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
4406 break;
4408 case ED_SIZE:
4410 ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
4411 break;
4413 case ED_PROTECTION:
4415 ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
4416 break;
4418 case ED_DATE:
4420 ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
4421 break;
4423 case ED_COMMENT:
4425 ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
4426 break;
4428 case ED_OWNER:
4430 ec.ec_MinSize = sizeof(struct ExAllData);
4431 break;
4434 SHOWVALUE(ec.ec_MinSize);
4436 offset = eac->eac_LastKey;
4438 ln = (struct LockNode *)lock->fl_Key;
4440 /* Check if we should restart scanning the directory
4441 * contents. This is tricky at best and may produce
4442 * irritating results :(
4444 if(ln->ln_RestartExamine)
4446 offset = 0;
4448 ln->ln_RestartExamine = FALSE;
4451 if(offset == 0)
4453 smba_stat_t st;
4455 SHOWMSG("first invocation");
4457 SHOWMSG("getting file attributes");
4458 error = smba_getattr(ln->ln_File,&st);
4459 if(error < 0)
4461 SHOWMSG("didn't work");
4462 error = MapErrnoToIoErr(error);
4463 eac->eac_LastKey = (ULONG)-1;
4464 goto out;
4467 if(NOT st.is_dir)
4469 SHOWMSG("lock does not refer to a directory");
4470 error = ERROR_OBJECT_WRONG_TYPE;
4471 eac->eac_LastKey = (ULONG)-1;
4472 goto out;
4476 SHOWMSG("calling 'smba_readdir'");
4477 SHOWVALUE(offset);
4479 count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
4481 SHOWVALUE(count);
4483 if(count == 0 || eac->eac_Entries == 0)
4485 SHOWMSG("nothing to be read");
4486 if(ec.ec_Error != OK)
4488 SHOWMSG("flagging an error");
4489 SHOWVALUE(ec.ec_Error);
4490 eac->eac_LastKey = (ULONG)-1;
4491 error = ec.ec_Error;
4494 goto out;
4496 else if (count == (-EIO))
4498 SHOWMSG("ouch! directory read error");
4499 eac->eac_LastKey = (ULONG)-1;
4501 error = ERROR_NO_DEFAULT_DIR;
4502 goto out;
4504 else if (count < 0)
4506 SHOWMSG("error whilst scanning");
4507 eac->eac_LastKey = (ULONG)-1;
4509 error = MapErrnoToIoErr(count);
4510 goto out;
4513 SHOWMSG("ok");
4514 result = DOSTRUE;
4516 out:
4518 #if DEBUG
4520 SHOWVALUE(eac->eac_Entries);
4522 while(ed != NULL)
4524 SHOWSTRING(ed->ed_Name);
4526 ed = ed->ed_Next;
4529 #endif /* DEBUG */
4531 (*error_ptr) = error;
4533 RETURN(result);
4534 return(result);
4537 /****************************************************************************/
4539 STATIC LONG
4540 Action_Find(
4541 LONG action,
4542 struct FileHandle * fh,
4543 struct FileLock * parent,
4544 APTR bcpl_name,
4545 SIPTR * error_ptr)
4547 LONG result = DOSFALSE;
4548 STRPTR parent_path = NULL;
4549 STRPTR full_name = NULL;
4550 LONG full_name_size;
4551 struct FileNode * fn = NULL;
4552 STRPTR parent_name;
4553 UBYTE name[MAX_FILENAME_LEN];
4554 BOOL create_new_file;
4555 LONG error;
4557 ENTER();
4559 switch(action)
4561 case ACTION_FINDINPUT:
4562 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
4563 break;
4565 case ACTION_FINDOUTPUT:
4566 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
4567 break;
4569 case ACTION_FINDUPDATE:
4570 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
4571 break;
4574 SHOWVALUE(parent);
4576 if(parent != NULL)
4578 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
4580 parent_name = ln->ln_FullName;
4582 else
4584 parent_name = NULL;
4587 ConvertBString(sizeof(name),name,bcpl_name);
4589 if (TranslateUTF8)
4591 UBYTE encoded_name[MAX_FILENAME_LEN];
4592 int encoded_name_len;
4593 LONG name_len = strlen(name);
4595 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
4596 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
4598 error = ERROR_INVALID_COMPONENT_NAME;
4599 goto out;
4602 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
4604 strlcpy(name,encoded_name,sizeof(name));
4606 else if (TranslateNames)
4608 TranslateCName(name,A2M);
4611 if(IsReservedName(FilePart(name)))
4613 error = ERROR_OBJECT_NOT_FOUND;
4614 goto out;
4617 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
4618 if(error != OK)
4619 goto out;
4621 /* Trying to open the root directory? */
4622 if(full_name == NULL)
4624 error = ERROR_OBJECT_WRONG_TYPE;
4625 goto out;
4628 fn = AllocateMemory(sizeof(*fn));
4629 if(fn == NULL)
4631 error = ERROR_NO_FREE_STORE;
4632 goto out;
4635 memset(fn,0,sizeof(*fn));
4637 fn->fn_Handle = fh;
4638 fn->fn_FullName = full_name;
4639 fn->fn_Mode = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK;
4641 error = CheckAccessModeCollision(full_name,fn->fn_Mode);
4642 if(error != OK)
4643 goto out;
4645 SHOWSTRING(full_name);
4647 if(action == ACTION_FINDOUTPUT)
4649 /* Definitely create a new file. */
4650 create_new_file = TRUE;
4652 else if (action == ACTION_FINDINPUT)
4654 /* Open an existing file for reading. */
4655 create_new_file = FALSE;
4657 else if (action == ACTION_FINDUPDATE)
4659 smba_file_t * file = NULL;
4660 smba_stat_t st;
4662 if(smba_open(ServerData,full_name,full_name_size,&file) == OK &&
4663 smba_getattr(file,&st) == OK)
4665 /* File apparently opens Ok and information on it
4666 * is available, don't try to replace it.
4668 create_new_file = FALSE;
4670 else
4672 /* We try to ignore the error here and assume
4673 * that the remainder of the file opening
4674 * procedure will produce a useful error
4675 * report. In the mean time, assume that the
4676 * file needs to be created.
4678 create_new_file = TRUE;
4681 if(file != NULL)
4682 smba_close(file);
4684 else
4686 /* What's that? */
4687 error = ERROR_ACTION_NOT_KNOWN;
4688 goto out;
4691 /* Create a new file? */
4692 if(create_new_file)
4694 smba_stat_t st;
4695 smba_file_t * dir;
4696 STRPTR base_name;
4697 LONG i;
4699 if(WriteProtected)
4701 error = ERROR_DISK_WRITE_PROTECTED;
4702 goto out;
4705 parent_path = AllocateMemory(strlen(full_name)+3);
4706 if(parent_path == NULL)
4708 error = ERROR_NO_FREE_STORE;
4709 goto out;
4712 strcpy(parent_path,full_name);
4713 base_name = NULL;
4714 for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
4716 if(parent_path[i] == SMB_PATH_SEPARATOR)
4718 if(i == 0)
4720 memmove(&parent_path[1],&parent_path[0],strlen(parent_path)+1);
4721 i++;
4724 parent_path[i] = '\0';
4726 base_name = &parent_path[i+1];
4727 break;
4731 SHOWMSG("creating a file; finding parent path first");
4732 SHOWSTRING(parent_path);
4734 error = smba_open(ServerData,parent_path,strlen(full_name)+3,&dir);
4735 if(error < 0)
4737 error = MapErrnoToIoErr(error);
4738 goto out;
4741 /* Only one attribute counts: the file should not be write protected. */
4742 memset(&st,0,sizeof(st));
4744 SHOWMSG("now trying to create the file");
4745 SHOWSTRING(base_name);
4747 error = smba_create(dir,base_name,&st);
4748 if(error < 0)
4750 SHOWMSG("didn't work.");
4751 SHOWVALUE(error);
4753 smba_close(dir);
4754 error = MapErrnoToIoErr(error);
4756 SHOWVALUE(error);
4758 goto out;
4761 SHOWMSG("good.");
4763 smba_close(dir);
4766 /* Now for the remainder... */
4767 error = smba_open(ServerData,full_name,full_name_size,&fn->fn_File);
4768 if(error < 0)
4770 error = MapErrnoToIoErr(error);
4771 goto out;
4774 fh->fh_Arg1 = (IPTR)fn;
4776 AddTail((struct List *)&FileList,(struct Node *)fn);
4777 result = DOSTRUE;
4779 out:
4781 if(result == DOSFALSE)
4783 FreeMemory(full_name);
4784 FreeMemory(fn);
4787 FreeMemory(parent_path);
4789 (*error_ptr) = error;
4791 RETURN(result);
4792 return(result);
4795 /****************************************************************************/
4797 STATIC LONG
4798 Action_Read(
4799 struct FileNode * fn,
4800 APTR mem,
4801 LONG length,
4802 SIPTR * error_ptr)
4804 LONG result = 0;
4805 LONG error = OK;
4807 ENTER();
4809 if(length > 0)
4811 result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
4812 if(result < 0)
4814 error = MapErrnoToIoErr(result);
4815 result = -1;
4816 goto out;
4819 fn->fn_Offset += result;
4822 out:
4824 (*error_ptr) = error;
4826 RETURN(result);
4827 return(result);
4830 /****************************************************************************/
4832 STATIC LONG
4833 Action_Write(
4834 struct FileNode * fn,
4835 APTR mem,
4836 LONG length,
4837 SIPTR * error_ptr)
4839 LONG result = DOSFALSE;
4840 LONG error = OK;
4842 ENTER();
4844 if(WriteProtected)
4846 error = ERROR_DISK_WRITE_PROTECTED;
4847 goto out;
4850 if(length > 0)
4852 result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
4853 if(result < 0)
4855 error = MapErrnoToIoErr(result);
4856 result = -1;
4857 goto out;
4860 fn->fn_Offset += result;
4863 out:
4865 (*error_ptr) = error;
4867 RETURN(result);
4868 return(result);
4871 /****************************************************************************/
4873 STATIC LONG
4874 Action_End(
4875 struct FileNode * fn,
4876 SIPTR * error_ptr)
4878 Remove((struct Node *)fn);
4880 smba_close(fn->fn_File);
4881 FreeMemory(fn->fn_FullName);
4882 FreeMemory(fn);
4884 (*error_ptr) = OK;
4885 return(DOSTRUE);
4888 /****************************************************************************/
4890 STATIC LONG
4891 Action_Seek(
4892 struct FileNode * fn,
4893 LONG position,
4894 LONG mode,
4895 SIPTR * error_ptr)
4897 LONG previous_position = fn->fn_Offset;
4898 LONG result = -1;
4899 LONG offset;
4900 LONG error;
4902 ENTER();
4904 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4905 #if 0
4907 switch(mode)
4909 case OFFSET_BEGINNING:
4911 mode = 0;
4912 break;
4914 case OFFSET_CURRENT:
4916 mode = 1;
4917 break;
4919 case OFFSET_END:
4921 mode = 2;
4922 break;
4924 default:
4926 error = ERROR_ACTION_NOT_KNOWN;
4927 goto out;
4930 error = smba_seek (fn->fn_File, position, mode, (off_t *) &offset);
4931 if(error < 0)
4933 error = MapErrnoToIoErr(error);
4934 goto out;
4937 #endif
4939 /* olsen: This is the original implementation. */
4940 #if 0
4942 smba_stat_t st;
4944 error = smba_getattr(fn->fn_File,&st);
4945 if(error < 0)
4947 error = MapErrnoToIoErr(error);
4948 goto out;
4951 offset = fn->fn_Offset;
4953 switch(mode)
4955 case OFFSET_BEGINNING:
4957 offset = position;
4958 break;
4960 case OFFSET_CURRENT:
4962 offset += position;
4963 break;
4965 case OFFSET_END:
4967 offset = st.size + position;
4968 break;
4970 default:
4972 error = ERROR_ACTION_NOT_KNOWN;
4973 goto out;
4976 if(offset < 0 || offset > st.size)
4978 error = ERROR_SEEK_ERROR;
4979 goto out;
4982 #endif
4984 /* olsen: This is a mix of the two above. First we calculate the absolute
4985 * position, then seek to that position. The SMB server is supposed
4986 * to do its housekeeping before the position is changed. I wish this
4987 * worked differently, but it seems we've got the best of both worlds
4988 * here...
4990 #if 1
4992 smba_stat_t st;
4994 switch(mode)
4996 case OFFSET_BEGINNING:
4998 offset = position;
4999 break;
5001 case OFFSET_CURRENT:
5003 offset = fn->fn_Offset + position;
5004 break;
5006 case OFFSET_END:
5008 error = smba_getattr(fn->fn_File,&st);
5009 if(error < 0)
5011 error = MapErrnoToIoErr(error);
5012 goto out;
5015 offset = st.size + position;
5016 break;
5018 default:
5020 error = ERROR_ACTION_NOT_KNOWN;
5021 goto out;
5024 if(offset < 0)
5026 error = ERROR_SEEK_ERROR;
5027 goto out;
5030 error = smba_seek (fn->fn_File, offset, 0, (off_t *) &offset);
5031 if(error < 0)
5033 error = MapErrnoToIoErr(error);
5034 goto out;
5037 #endif
5039 error = OK;
5041 fn->fn_Offset = offset;
5043 result = previous_position;
5045 out:
5047 (*error_ptr) = error;
5049 RETURN(result);
5050 return(result);
5053 /****************************************************************************/
5055 STATIC LONG
5056 Action_SetFileSize(
5057 struct FileNode * fn,
5058 LONG position,
5059 LONG mode,
5060 SIPTR * error_ptr)
5062 smba_stat_t st;
5063 LONG result = -1;
5064 LONG error;
5065 long offset;
5067 ENTER();
5069 if(WriteProtected)
5071 error = ERROR_DISK_WRITE_PROTECTED;
5072 goto out;
5075 error = smba_getattr(fn->fn_File,&st);
5076 if(error < 0)
5078 error = MapErrnoToIoErr(error);
5079 goto out;
5082 offset = fn->fn_Offset;
5084 switch(mode)
5086 case OFFSET_BEGINNING:
5088 offset = position;
5089 break;
5091 case OFFSET_CURRENT:
5093 offset += position;
5094 break;
5096 case OFFSET_END:
5098 offset = st.size + position;
5099 break;
5101 default:
5103 error = ERROR_ACTION_NOT_KNOWN;
5104 goto out;
5107 if(offset < 0)
5109 error = ERROR_SEEK_ERROR;
5110 goto out;
5113 st.atime = -1;
5114 st.ctime = -1;
5115 st.mtime = -1;
5116 st.size = offset;
5118 error = smba_setattr(fn->fn_File,&st);
5119 if(error < 0)
5121 error = MapErrnoToIoErr(error);
5122 goto out;
5125 if(fn->fn_Offset > offset)
5126 fn->fn_Offset = offset;
5128 result = offset;
5130 out:
5132 (*error_ptr) = error;
5134 RETURN(result);
5135 return(result);
5138 /****************************************************************************/
5140 STATIC LONG
5141 Action_SetDate(
5142 struct FileLock * parent,
5143 APTR bcpl_name,
5144 struct DateStamp * ds,
5145 SIPTR * error_ptr)
5147 LONG result = DOSFALSE;
5148 STRPTR full_name = NULL;
5149 LONG full_name_size;
5150 smba_file_t * file = NULL;
5151 STRPTR parent_name;
5152 UBYTE name[MAX_FILENAME_LEN];
5153 smba_stat_t st;
5154 LONG seconds;
5155 LONG error;
5157 ENTER();
5159 if(WriteProtected)
5161 error = ERROR_DISK_WRITE_PROTECTED;
5162 goto out;
5165 SHOWVALUE(parent);
5167 if(parent != NULL)
5169 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5171 parent_name = ln->ln_FullName;
5173 else
5175 parent_name = NULL;
5178 ConvertBString(sizeof(name),name,bcpl_name);
5180 if (TranslateUTF8)
5182 UBYTE encoded_name[MAX_FILENAME_LEN];
5183 int encoded_name_len;
5184 LONG name_len = strlen(name);
5186 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
5187 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
5189 error = ERROR_INVALID_COMPONENT_NAME;
5190 goto out;
5193 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
5195 strlcpy(name,encoded_name,sizeof(name));
5197 else if (TranslateNames)
5199 TranslateCName(name,A2M);
5202 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5203 if(error != OK)
5204 goto out;
5206 /* Trying to change the date of the root directory? */
5207 if(full_name == NULL)
5209 error = ERROR_OBJECT_IN_USE;
5210 goto out;
5213 SHOWSTRING(full_name);
5215 error = smba_open(ServerData,full_name,full_name_size,&file);
5216 if(error < 0)
5218 error = MapErrnoToIoErr(error);
5219 goto out;
5222 error = smba_getattr(file,&st);
5223 if(error < 0)
5225 error = MapErrnoToIoErr(error);
5226 goto out;
5229 seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
5231 st.atime = -1;
5232 st.ctime = -1;
5233 st.mtime = seconds + UNIX_TIME_OFFSET + GetTimeZoneDelta();
5234 st.size = -1;
5236 error = smba_setattr(file,&st);
5237 if(error < 0)
5239 error = MapErrnoToIoErr(error);
5240 goto out;
5243 result = DOSTRUE;
5245 out:
5247 FreeMemory(full_name);
5249 if(file != NULL)
5250 smba_close(file);
5252 (*error_ptr) = error;
5254 RETURN(result);
5255 return(result);
5258 /****************************************************************************/
5260 STATIC LONG
5261 Action_ExamineFH(
5262 struct FileNode * fn,
5263 struct FileInfoBlock * fib,
5264 SIPTR * error_ptr)
5266 LONG result = DOSFALSE;
5267 smba_stat_t st;
5268 LONG error;
5269 LONG seconds;
5270 STRPTR name;
5271 LONG name_len;
5272 LONG i;
5274 ENTER();
5276 error = smba_getattr(fn->fn_File,&st);
5277 if(error < 0)
5279 error = MapErrnoToIoErr(error);
5280 goto out;
5283 name = fn->fn_FullName;
5284 name_len = strlen(name);
5286 for(i = name_len ; i >= 0 ; i--)
5288 if(name[i] == SMB_PATH_SEPARATOR)
5290 name = &name[i+1];
5291 break;
5295 /* Just checking: will the name fit? */
5296 if(name_len >= sizeof(fib->fib_FileName))
5298 error = ERROR_INVALID_COMPONENT_NAME;
5299 goto out;
5302 memset(fib,0,sizeof(*fib));
5304 if(TranslateUTF8)
5306 UBYTE decoded_name[MAX_FILENAME_LEN];
5307 int decoded_name_len;
5309 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
5310 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
5312 error = ERROR_INVALID_COMPONENT_NAME;
5313 goto out;
5316 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
5318 fib->fib_FileName[0] = decoded_name_len;
5319 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
5321 else
5323 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
5325 if(TranslateNames)
5326 TranslateBName(fib->fib_FileName,M2A);
5329 fib->fib_DirEntryType = ST_FILE;
5330 fib->fib_EntryType = ST_FILE;
5331 fib->fib_NumBlocks = (st.size + 511) / 512;
5332 fib->fib_Size = st.size;
5333 fib->fib_DiskKey = -1;
5335 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
5336 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
5338 if(st.is_wp)
5339 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
5341 /* Careful: the 'archive' attribute has exactly the opposite
5342 * meaning in the Amiga and the SMB worlds.
5344 if(NOT st.is_archive)
5345 fib->fib_Protection |= FIBF_ARCHIVE;
5347 if(st.is_system)
5348 fib->fib_Protection |= FIBF_PURE;
5350 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
5351 seconds = (st.mtime == 0 ? st.ctime : st.mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
5352 if(seconds < 0)
5353 seconds = 0;
5355 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
5356 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
5357 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
5359 result = DOSTRUE;
5361 out:
5363 (*error_ptr) = error;
5365 RETURN(result);
5366 return(result);
5369 /****************************************************************************/
5371 STATIC BPTR
5372 Action_ParentFH(
5373 struct FileNode * fn,
5374 SIPTR * error_ptr)
5376 BPTR result = ZERO;
5377 struct LockNode * ln = NULL;
5378 LONG error;
5379 STRPTR full_name;
5380 LONG full_name_size;
5381 LONG i;
5383 ENTER();
5385 full_name_size = strlen(fn->fn_FullName)+3;
5386 if(full_name_size < SMB_MAXNAMELEN+1)
5387 full_name_size = SMB_MAXNAMELEN+1;
5389 full_name = AllocateMemory(full_name_size);
5390 if(full_name == NULL)
5392 error = ERROR_NO_FREE_STORE;
5393 goto out;
5396 strcpy(full_name,fn->fn_FullName);
5398 for(i = strlen(full_name)-1 ; i >= 0 ; i--)
5400 if(i == 0)
5402 strcpy(full_name,SMB_ROOT_DIR_NAME);
5403 break;
5405 else if (full_name[i] == SMB_PATH_SEPARATOR)
5407 full_name[i] = '\0';
5408 break;
5412 ln = AllocateMemory(sizeof(*ln));
5413 if(ln == NULL)
5415 error = ERROR_NO_FREE_STORE;
5416 goto out;
5419 memset(ln,0,sizeof(*ln));
5421 ln->ln_FileLock.fl_Key = (IPTR)ln;
5422 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5423 ln->ln_FileLock.fl_Task = FileSystemPort;
5424 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5425 ln->ln_FullName = full_name;
5427 SHOWSTRING(full_name);
5429 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5430 if(error < 0)
5432 error = MapErrnoToIoErr(error);
5433 goto out;
5436 AddTail((struct List *)&LockList,(struct Node *)ln);
5437 result = MKBADDR(&ln->ln_FileLock);
5438 SHOWVALUE(&ln->ln_FileLock);
5440 out:
5442 if(result == ZERO)
5444 FreeMemory(ln);
5445 FreeMemory(full_name);
5448 (*error_ptr) = error;
5450 RETURN(result);
5451 return(result);
5454 /****************************************************************************/
5456 STATIC BPTR
5457 Action_CopyDirFH(
5458 struct FileNode * fn,
5459 SIPTR * error_ptr)
5461 BPTR result = ZERO;
5462 struct LockNode * ln = NULL;
5463 STRPTR full_name = NULL;
5464 LONG full_name_size;
5465 LONG error;
5467 ENTER();
5469 if(fn->fn_Mode != SHARED_LOCK)
5471 error = ERROR_OBJECT_IN_USE;
5472 goto out;
5475 full_name_size = strlen(fn->fn_FullName)+3;
5476 if(full_name_size < SMB_MAXNAMELEN+1)
5477 full_name_size = SMB_MAXNAMELEN+1;
5479 full_name = AllocateMemory(full_name_size);
5480 if(full_name == NULL)
5482 error = ERROR_NO_FREE_STORE;
5483 goto out;
5486 strcpy(full_name,fn->fn_FullName);
5488 ln = AllocateMemory(sizeof(*ln));
5489 if(ln == NULL)
5491 error = ERROR_NO_FREE_STORE;
5492 goto out;
5495 memset(ln,0,sizeof(*ln));
5497 ln->ln_FileLock.fl_Key = (IPTR)ln;
5498 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5499 ln->ln_FileLock.fl_Task = FileSystemPort;
5500 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5501 ln->ln_FullName = full_name;
5503 SHOWSTRING(full_name);
5505 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5506 if(error < 0)
5508 error = MapErrnoToIoErr(error);
5509 goto out;
5512 AddTail((struct List *)&LockList,(struct Node *)ln);
5513 result = MKBADDR(&ln->ln_FileLock);
5514 SHOWVALUE(&ln->ln_FileLock);
5516 out:
5518 if(result == ZERO)
5520 FreeMemory(ln);
5521 FreeMemory(full_name);
5524 (*error_ptr) = error;
5526 RETURN(result);
5527 return(result);
5530 /****************************************************************************/
5532 STATIC LONG
5533 Action_FHFromLock(
5534 struct FileHandle * fh,
5535 struct FileLock * fl,
5536 SIPTR * error_ptr)
5538 LONG result = DOSFALSE;
5539 struct FileNode * fn;
5540 struct LockNode * ln;
5541 LONG error = OK;
5543 ENTER();
5545 SHOWVALUE(fl);
5547 fn = AllocateMemory(sizeof(*fn));
5548 if(fn == NULL)
5550 error = ERROR_NO_FREE_STORE;
5551 goto out;
5554 memset(fn,0,sizeof(*fn));
5556 ln = (struct LockNode *)fl->fl_Key;
5558 fn->fn_Handle = fh;
5559 fn->fn_FullName = ln->ln_FullName;
5560 fn->fn_File = ln->ln_File;
5561 fn->fn_Mode = fl->fl_Access;
5563 Remove((struct Node *)ln);
5564 FreeMemory(ln);
5566 fh->fh_Arg1 = (IPTR)fn;
5568 AddTail((struct List *)&FileList,(struct Node *)fn);
5569 result = DOSTRUE;
5571 out:
5573 (*error_ptr) = error;
5575 RETURN(result);
5576 return(result);
5579 /****************************************************************************/
5581 STATIC LONG
5582 Action_RenameDisk(
5583 APTR bcpl_name,
5584 SIPTR * error_ptr)
5586 LONG result = DOSFALSE;
5587 LONG error = OK;
5588 STRPTR old_name;
5589 STRPTR new_name;
5590 UBYTE * name;
5591 LONG len;
5593 ENTER();
5595 if(NOT VolumeNodeAdded)
5597 error = ERROR_OBJECT_IN_USE;
5598 goto out;
5601 if(WriteProtected)
5603 error = ERROR_DISK_WRITE_PROTECTED;
5604 goto out;
5607 /* Now for the really interesting part; the new name
5608 * is to be a NUL-terminated BCPL string, and as such
5609 * must be allocated via AllocVec().
5612 name = bcpl_name;
5614 len = name[0];
5616 new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
5617 if(new_name == NULL)
5619 error = ERROR_NO_FREE_STORE;
5620 goto out;
5623 new_name[0] = len;
5624 memcpy(&new_name[1],&name[1],len);
5625 new_name[len+1] = '\0';
5627 Forbid();
5629 old_name = BADDR(VolumeNode->dol_Name);
5630 VolumeNode->dol_Name = MKBADDR(new_name);
5632 Permit();
5634 FreeVec(old_name);
5636 SendDiskChange(IECLASS_DISKINSERTED);
5638 result = DOSTRUE;
5640 out:
5642 (*error_ptr) = error;
5644 RETURN(result);
5645 return(result);
5648 /****************************************************************************/
5650 STATIC LONG
5651 Action_ChangeMode(
5652 LONG type,
5653 APTR object,
5654 LONG new_mode,
5655 SIPTR * error_ptr)
5657 LONG result = DOSFALSE;
5658 struct FileLock * fl = NULL;
5659 struct FileNode * fn = NULL;
5660 struct LockNode * ln = NULL;
5661 STRPTR name;
5662 LONG old_mode;
5663 LONG error = OK;
5665 ENTER();
5667 /* Sanity check; verify parameters */
5668 if((type != CHANGE_LOCK && type != CHANGE_FH) ||
5669 (new_mode != EXCLUSIVE_LOCK && new_mode != SHARED_LOCK))
5671 error = ERROR_ACTION_NOT_KNOWN;
5672 goto out;
5675 /* Now obtain the data structures, name and mode
5676 * associated with the object in question.
5678 if(type == CHANGE_LOCK)
5680 fl = object;
5681 ln = (struct LockNode *)fl->fl_Key;
5682 name = ln->ln_FullName;
5683 old_mode = fl->fl_Access;
5685 else
5687 struct FileHandle * fh = object;
5689 fn = (struct FileNode *)fh->fh_Arg1;
5690 name = fn->fn_FullName;
5691 old_mode = fn->fn_Mode;
5694 /* Do we need to change anything at all? */
5695 if(new_mode == old_mode)
5697 result = DOSTRUE;
5698 goto out;
5701 /* This is the easiest case; change an
5702 * exclusive access mode to a shared
5703 * access mode. Since the original mode
5704 * can be used by one object only,
5705 * we get away by updating the mode
5706 * value.
5708 if(new_mode == SHARED_LOCK)
5710 if(type == CHANGE_LOCK)
5711 fl->fl_Access = new_mode;
5712 else
5713 fn->fn_Mode = new_mode;
5715 result = DOSTRUE;
5716 goto out;
5719 /* Is there another shared access lock
5720 * which refers to the same object?
5722 if(FindLockNode(name,ln) != NULL)
5724 error = ERROR_OBJECT_IN_USE;
5725 goto out;
5728 /* Is there another shared access file
5729 * which refers to the same object?
5731 if(FindFileNode(name,fn) != NULL)
5733 error = ERROR_OBJECT_IN_USE;
5734 goto out;
5737 /* There is just one single reference
5738 * to this object; change the mode
5739 * and quit.
5741 if(type == CHANGE_LOCK)
5742 fl->fl_Access = new_mode;
5743 else
5744 fn->fn_Mode = new_mode;
5746 result = DOSTRUE;
5748 out:
5750 (*error_ptr) = error;
5752 RETURN(result);
5753 return(result);
5756 /****************************************************************************/
5758 STATIC LONG
5759 Action_WriteProtect(
5760 LONG flag,
5761 ULONG key,
5762 SIPTR * error_ptr)
5764 LONG result = DOSFALSE;
5765 LONG error = OK;
5767 ENTER();
5769 if(flag == DOSFALSE)
5771 if(WriteProtected)
5773 if(key != WriteProtectKey)
5775 error = ERROR_INVALID_LOCK;
5776 goto out;
5779 WriteProtected = FALSE;
5781 if(VolumeNodeAdded)
5783 SendDiskChange(IECLASS_DISKREMOVED);
5784 SendDiskChange(IECLASS_DISKINSERTED);
5788 else
5790 if(NOT WriteProtected)
5792 WriteProtected = TRUE;
5793 WriteProtectKey = key;
5795 if(VolumeNodeAdded)
5797 SendDiskChange(IECLASS_DISKREMOVED);
5798 SendDiskChange(IECLASS_DISKINSERTED);
5801 else
5803 error = ERROR_INVALID_LOCK;
5804 goto out;
5808 result = DOSTRUE;
5810 out:
5812 (*error_ptr) = error;
5814 RETURN(result);
5815 return(result);
5818 /****************************************************************************/
5820 STATIC LONG
5821 Action_MoreCache(
5822 LONG buffer_delta,
5823 SIPTR * error_ptr)
5825 LONG result;
5826 int old_size;
5828 ENTER();
5830 old_size = smba_get_dircache_size(ServerData);
5832 result = smba_change_dircache_size(ServerData,old_size + buffer_delta);
5834 if(result == old_size && buffer_delta != 0)
5836 result = DOSFALSE;
5837 (*error_ptr) = ERROR_NO_FREE_STORE;
5840 RETURN(result);
5841 return(result);
5844 /****************************************************************************/
5846 STATIC LONG
5847 Action_SetComment(
5848 struct FileLock * parent,
5849 APTR bcpl_name,
5850 APTR bcpl_comment,
5851 SIPTR * error_ptr)
5853 LONG result = DOSFALSE;
5854 STRPTR full_name = NULL;
5855 LONG full_name_size;
5856 smba_file_t * file = NULL;
5857 STRPTR parent_name;
5858 UBYTE name[MAX_FILENAME_LEN];
5859 UBYTE comment[80];
5860 LONG error;
5862 ENTER();
5864 if(WriteProtected)
5866 error = ERROR_DISK_WRITE_PROTECTED;
5867 goto out;
5870 SHOWVALUE(parent);
5872 if(parent != NULL)
5874 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5876 parent_name = ln->ln_FullName;
5878 else
5880 parent_name = NULL;
5883 ConvertBString(sizeof(name),name,bcpl_name);
5885 if (TranslateUTF8)
5887 UBYTE encoded_name[MAX_FILENAME_LEN];
5888 int encoded_name_len;
5889 LONG name_len = strlen(name);
5891 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
5892 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
5894 error = ERROR_INVALID_COMPONENT_NAME;
5895 goto out;
5898 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
5900 strlcpy(name,encoded_name,sizeof(name));
5902 else if (TranslateNames)
5904 TranslateCName(name,A2M);
5907 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5908 if(error != OK)
5909 goto out;
5911 /* Trying to change the comment of the root directory? */
5912 if(full_name == NULL)
5914 error = ERROR_OBJECT_IN_USE;
5915 goto out;
5918 SHOWSTRING(full_name);
5920 error = smba_open(ServerData,full_name,full_name_size,&file);
5921 if(error < 0)
5923 error = MapErrnoToIoErr(error);
5924 goto out;
5927 ConvertBString(sizeof(comment),comment,bcpl_comment);
5929 SHOWSTRING(comment);
5931 /* All this work and we're only doing something very silly... */
5932 if(strlen(comment) > 0)
5934 error = ERROR_COMMENT_TOO_BIG;
5935 goto out;
5938 result = DOSTRUE;
5940 out:
5942 FreeMemory(full_name);
5944 if(file != NULL)
5945 smba_close(file);
5947 (*error_ptr) = error;
5949 RETURN(result);
5950 return(result);
5953 /****************************************************************************/
5955 STATIC LONG
5956 Action_LockRecord (
5957 struct FileNode * fn,
5958 LONG offset,
5959 LONG length,
5960 LONG mode,
5961 ULONG timeout,
5962 SIPTR * error_ptr)
5964 LONG result = DOSFALSE;
5965 LONG error;
5966 LONG umode;
5968 /* Sanity checks... */
5969 if (mode < REC_EXCLUSIVE || mode > REC_SHARED_IMMED)
5971 error = ERROR_ACTION_NOT_KNOWN;
5972 goto out;
5975 /* Invalid offset, size or integer overflow? */
5976 if (offset < 0 || length <= 0 || offset + length < offset)
5978 error = ERROR_LOCK_COLLISION;
5979 goto out;
5982 if ((mode == REC_SHARED) || (mode == REC_SHARED_IMMED))
5983 umode = 1;
5984 else
5985 umode = 0;
5987 if ((mode == REC_SHARED_IMMED) || (mode == REC_EXCLUSIVE_IMMED))
5988 timeout = 0;
5990 if (timeout > 0)
5992 if (timeout > 214748364)
5993 timeout = ~0; /* wait forever */
5994 else
5995 timeout *= 20; /* milliseconds instead of Ticks */
5998 error = smba_lockrec (fn->fn_File, offset, length, umode, 0, (long)timeout);
5999 if(error < 0)
6001 error = MapErrnoToIoErr(error);
6002 goto out;
6005 result = DOSTRUE;
6007 out:
6009 (*error_ptr) = error;
6011 RETURN(result);
6012 return(result);
6015 /****************************************************************************/
6017 STATIC LONG
6018 Action_FreeRecord (
6019 struct FileNode * fn,
6020 LONG offset,
6021 LONG length,
6022 SIPTR * error_ptr)
6024 LONG result = DOSFALSE;
6025 LONG error;
6027 /* Sanity checks... */
6028 if(offset < 0 || length <= 0 || offset + length < offset)
6030 error = ERROR_RECORD_NOT_LOCKED;
6031 goto out;
6034 error = smba_lockrec (fn->fn_File, offset, length, 2, -1, 0);
6035 if (error < 0)
6037 error = MapErrnoToIoErr(error);
6038 goto out;
6041 result = DOSTRUE;
6043 out:
6045 (*error_ptr) = error;
6047 RETURN(result);
6048 return(result);
6051 /****************************************************************************/
6053 STATIC VOID
6054 HandleFileSystem(VOID)
6056 struct Process * this_process = (struct Process *)FindTask(NULL);
6057 BOOL sign_off = FALSE;
6058 BYTE old_priority;
6059 ULONG signals;
6060 BOOL done;
6062 ENTER();
6064 DisplayErrorList();
6065 Quiet = TRUE;
6067 done = FALSE;
6069 /* Raise the Task priority of the file system to 10
6070 * unless it already is running at priority 10 or higher.
6072 Forbid();
6074 old_priority = this_process->pr_Task.tc_Node.ln_Pri;
6075 if(old_priority < 10)
6076 SetTaskPri((struct Task *)this_process, 10);
6078 Permit();
6082 signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << FileSystemPort->mp_SigBit));
6084 if(signals & (1UL << FileSystemPort->mp_SigBit))
6086 struct DosPacket * dp;
6087 struct Message * mn;
6088 SIPTR res1,res2;
6090 while((mn = GetMsg(FileSystemPort)) != NULL)
6092 dp = (struct DosPacket *)mn->mn_Node.ln_Name;
6094 D(("got packet; sender '%s'",((struct Node *)dp->dp_Port->mp_SigTask)->ln_Name));
6096 res2 = 0;
6098 if (mn->mn_Node.ln_Type == NT_REPLYMSG)
6100 LONG max_transmit = -1;
6101 if(args.MaxTransmit != NULL)
6102 max_transmit = (*args.MaxTransmit);
6104 AddVolume(
6105 args.DeviceName,
6106 args.VolumeName,
6107 args.Service,
6108 args.Workgroup,
6109 args.UserName,
6110 args.Password,
6111 args.ClientName,
6112 args.ServerName,
6113 (args.CacheSize != NULL) ? *args.CacheSize : 0,
6114 max_transmit,
6115 !args.NetBIOSTransport /* Use raw SMB transport instead of NetBIOS transport? */
6117 continue;
6119 if(!VolumeNodeAdded && dp->dp_Action != ACTION_STARTUP)
6121 res1 = DOSFALSE;
6122 res2 = ERROR_NO_DISK;
6123 ReplyPkt(dp,res1,res2);
6124 continue;
6126 switch(dp->dp_Action)
6128 case ACTION_STARTUP:
6129 /* FSSM,DeviceNode -> Bool */
6131 res1 = (IPTR)Action_Startup(
6132 (struct FileSysStartupMsg *)BADDR(dp->dp_Arg2),
6133 (struct DosList *)BADDR(dp->dp_Arg3),&res2);
6134 if(!res1)
6135 Quit = TRUE;
6136 break;
6138 case ACTION_DIE:
6140 SHOWMSG("ACTION_DIE");
6141 if(IsListEmpty(&FileList) && IsListEmpty(&LockList))
6143 SHOWMSG("no locks or files pending; quitting");
6145 res1 = DOSTRUE;
6147 else
6149 SHOWMSG("locks or files still pending; cannot quit yet");
6151 res1 = DOSFALSE;
6152 res2 = ERROR_OBJECT_IN_USE;
6155 Quit = TRUE;
6156 break;
6158 case ACTION_CURRENT_VOLUME:
6159 /* (Ignore) -> VolumeNode */
6161 res1 = (IPTR)MKBADDR(VolumeNode);
6162 break;
6164 case ACTION_LOCATE_OBJECT:
6165 /* Lock,Name,Mode -> Lock */
6167 res1 = (IPTR)Action_LocateObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6168 break;
6170 case ACTION_RENAME_DISK:
6171 /* Name -> Bool */
6173 res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
6174 break;
6176 case ACTION_FREE_LOCK:
6177 /* Lock -> Bool */
6179 res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6180 break;
6182 case ACTION_DELETE_OBJECT:
6183 /* Lock,Name -> Bool */
6185 res1 = Action_DeleteObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6186 break;
6188 case ACTION_RENAME_OBJECT:
6189 /* Source lock,source name,destination lock,destination name -> Bool */
6191 res1 = Action_RenameObject((struct FileLock *)BADDR(dp->dp_Arg1),BADDR(dp->dp_Arg2),
6192 (struct FileLock *)BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6194 break;
6196 case ACTION_MORE_CACHE:
6197 /* Buffer delta -> Total number of buffers */
6199 /* NOTE: documentation for this packet type is inconsistent;
6200 * in the 'good old' 1.x days 'res1' was documented as
6201 * the total number of buffers to be returned. In the
6202 * 2.x documentation it is said that 'res1' should
6203 * return the success code, with 'res2' to hold the
6204 * total number of buffers. However, the 'AddBuffers'
6205 * shell command doesn't work that way, and the
6206 * dos.library implementation of 'AddBuffers()' doesn't
6207 * work that way either. The 1.3 'AddBuffers' command
6208 * appears to treat a zero result as failure and a
6209 * non-zero result as success, which suggests that this
6210 * is how the packet is supposed to work, contrary to
6211 * what the official documentation says.
6213 res1 = Action_MoreCache(dp->dp_Arg1,&res2);
6214 break;
6216 case ACTION_COPY_DIR:
6217 /* Lock -> Lock */
6219 res1 = (IPTR)Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6220 break;
6222 case ACTION_SET_PROTECT:
6223 /* (Ignore),Lock,Name,Mask -> Bool */
6225 res1 = Action_SetProtect((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),dp->dp_Arg4,&res2);
6226 break;
6228 case ACTION_CREATE_DIR:
6229 /* Lock,Name -> Lock */
6231 res1 = (IPTR)Action_CreateDir((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6232 break;
6234 case ACTION_EXAMINE_OBJECT:
6235 /* FileLock,FileInfoBlock -> Bool */
6237 res1 = Action_ExamineObject((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6238 break;
6240 case ACTION_EXAMINE_NEXT:
6241 /* FileLock,FileInfoBlock -> Bool */
6243 res1 = Action_ExamineNext((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6244 break;
6246 case ACTION_DISK_INFO:
6247 /* InfoData -> Bool */
6249 Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
6250 res1 = DOSTRUE;
6251 res2 = 0;
6252 break;
6254 case ACTION_INFO:
6255 /* FileLock,InfoData -> Bool */
6257 res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
6258 break;
6260 case ACTION_SET_COMMENT:
6261 /* (Ignore),FileLock,Name,Comment -> Bool */
6263 res1 = Action_SetComment((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6264 break;
6266 case ACTION_PARENT:
6267 /* Lock -> Lock */
6269 res1 = (IPTR)Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6270 break;
6272 case ACTION_INHIBIT:
6274 SHOWMSG("ACTION_INHIBIT");
6275 res1 = DOSTRUE;
6276 break;
6278 case ACTION_SET_DATE:
6279 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
6281 res1 = Action_SetDate((struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),(struct DateStamp *)dp->dp_Arg4,&res2);
6282 break;
6284 case ACTION_SAME_LOCK:
6285 /* Lock,Lock -> Bool */
6287 res1 = Action_SameLock((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6288 break;
6290 case ACTION_READ:
6291 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6293 res1 = Action_Read((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6294 break;
6296 case ACTION_WRITE:
6297 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6299 res1 = Action_Write((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6300 break;
6302 case ACTION_FINDUPDATE:
6303 case ACTION_FINDINPUT:
6304 case ACTION_FINDOUTPUT:
6305 /* FileHandle,FileLock,Name -> Bool */
6307 res1 = Action_Find(dp->dp_Action,(struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),&res2);
6308 break;
6310 case ACTION_END:
6311 /* FileHandle->fh_Arg1 -> Bool */
6313 res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
6314 break;
6316 case ACTION_SEEK:
6317 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6319 res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6320 break;
6322 case ACTION_SET_FILE_SIZE:
6323 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
6325 res1 = Action_SetFileSize((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6326 break;
6328 case ACTION_WRITE_PROTECT:
6329 /* Flag,Key -> Bool */
6331 res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
6332 break;
6334 case ACTION_FH_FROM_LOCK:
6335 /* FileHandle(BPTR),FileLock -> Bool */
6337 res1 = Action_FHFromLock((struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6338 break;
6340 case ACTION_IS_FILESYSTEM:
6342 SHOWMSG("ACTION_IS_FILESYSTEM");
6343 res1 = DOSTRUE;
6344 break;
6346 case ACTION_CHANGE_MODE:
6347 /* Type,Object,Mode -> Bool */
6349 res1 = Action_ChangeMode(dp->dp_Arg1,(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6350 break;
6352 case ACTION_COPY_DIR_FH:
6353 /* FileHandle->fh_Arg1 -> Bool */
6355 res1 = (IPTR)Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
6356 break;
6358 case ACTION_PARENT_FH:
6359 /* FileHandle->fh_Arg1 -> Bool */
6361 res1 = (IPTR)Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
6362 break;
6364 case ACTION_EXAMINE_ALL:
6365 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6367 res1 = Action_ExamineAll((struct FileLock *)BADDR(dp->dp_Arg1),(struct ExAllData *)dp->dp_Arg2,
6368 dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2);
6370 break;
6372 case ACTION_EXAMINE_FH:
6373 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
6375 res1 = Action_ExamineFH((struct FileNode *)dp->dp_Arg1,(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6376 break;
6378 case ACTION_EXAMINE_ALL_END:
6379 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6381 res1 = DOSTRUE;
6382 break;
6384 case ACTION_LOCK_RECORD:
6385 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
6386 res1 = Action_LockRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,dp->dp_Arg4,(ULONG)dp->dp_Arg5,&res2);
6387 break;
6389 case ACTION_FREE_RECORD:
6390 /* FileHandle->fh_Arg1,position,length -> Bool */
6391 res1 = Action_FreeRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6392 break;
6394 default:
6396 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
6398 /* Return -1 for ACTION_READ_LINK, for which DOSFALSE (= 0)
6399 * would otherwise be a valid response. Bug fix contributed
6400 * by Harry 'Piru' Sintonen.
6402 res1 = (dp->dp_Action == ACTION_READ_LINK) ? -1 : DOSFALSE;
6403 res2 = ERROR_ACTION_NOT_KNOWN;
6405 break;
6408 SHOWVALUE(res1);
6409 SHOWVALUE(res2);
6411 ReplyPkt(dp,res1,res2);
6413 D(("\n"));
6417 #if DEBUG
6419 if(signals & SIGBREAKF_CTRL_F)
6421 struct FileNode * fn;
6422 struct LockNode * ln;
6424 D(("list of open files:"));
6426 for(fn = (struct FileNode *)FileList.mlh_Head ;
6427 fn->fn_MinNode.mln_Succ != NULL ;
6428 fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
6430 D((" name='%s'",fn->fn_FullName));
6431 D((" mode=%ld, offset=%ld",fn->fn_Mode,fn->fn_Offset));
6432 D((""));
6435 D(("list of allocated locks:"));
6437 for(ln = (struct LockNode *)LockList.mlh_Head ;
6438 ln->ln_MinNode.mln_Succ != NULL ;
6439 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
6441 D((" name='%s'",ln->ln_FullName));
6442 D((" mode=%ld",ln->ln_FileLock.fl_Access));
6443 D((""));
6447 #endif /* DEBUG */
6449 if(signals & SIGBREAKF_CTRL_C)
6450 Quit = TRUE;
6452 if(Quit)
6454 if(IsListEmpty(&FileList) && IsListEmpty(&LockList))
6456 SHOWMSG("no locks or files pending; quitting");
6457 done = TRUE;
6459 else
6461 SHOWMSG("locks or files still pending; cannot quit yet");
6465 while(NOT done);
6467 /* Restore the priority of the file system, unless the priority
6468 * has already been changed.
6470 Forbid();
6472 if(old_priority < 10 && this_process->pr_Task.tc_Node.ln_Pri == 10)
6473 SetTaskPri((struct Task *)this_process, old_priority);
6475 Permit();
6477 if(sign_off)
6478 LocalPrintf("stopped.\n");
6480 LEAVE();
6483 /****************************************************************************/
6486 * Copy src to string dst of size siz. At most siz-1 characters
6487 * will be copied. Always NUL terminates (unless siz == 0).
6488 * Returns strlen(src); if retval >= siz, truncation occurred.
6490 size_t
6491 strlcpy(char *dst, const char *src, size_t siz)
6493 char *d = dst;
6494 const char *s = src;
6495 size_t n = siz;
6496 size_t result;
6498 /* Copy as many bytes as will fit */
6499 if(n != 0 && --n != 0)
6503 if(((*d++) = (*s++)) == '\0')
6504 break;
6506 while(--n != 0);
6509 /* Not enough room in dst, add NUL and traverse rest of src */
6510 if(n == 0)
6512 if(siz != 0)
6513 (*d) = '\0'; /* NUL-terminate dst */
6515 while((*s++) != '\0')
6519 result = s - src - 1; /* count does not include NUL */
6521 return(result);
6525 * Appends src to string dst of size siz (unlike strncat, siz is the
6526 * full size of dst, not space left). At most siz-1 characters
6527 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
6528 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
6529 * If retval >= siz, truncation occurred.
6531 size_t
6532 strlcat(char *dst, const char *src, size_t siz)
6534 char *d = dst;
6535 const char *s = src;
6536 size_t n = siz;
6537 size_t dlen;
6538 size_t result;
6540 /* Find the end of dst and adjust bytes left but don't go past end */
6541 while(n-- != 0 && (*d) != '\0')
6542 d++;
6544 dlen = d - dst;
6545 n = siz - dlen;
6547 if(n == 0)
6549 result = dlen + strlen(s);
6551 else
6553 while((*s) != '\0')
6555 if(n != 1)
6557 (*d++) = (*s);
6558 n--;
6561 s++;
6564 (*d) = '\0';
6566 result = dlen + (s - src); /* count does not include NUL */
6569 return(result);