Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / network / smbfs / source_code / main.c
blobf325bcc1722da8cdba2c62a48c3751bb219fb587
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, 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 DeleteMsgPort(FileSystemPort);
1672 FileSystemPort = NULL;
1675 if(WBStartup == NULL && send_disk_change)
1676 SendDiskChange(IECLASS_DISKREMOVED);
1678 #if defined(__amigaos4__)
1680 if(ITimer != NULL)
1682 DropInterface((struct Interface *)ITimer);
1683 ITimer = NULL;
1686 #endif /* __amigaos4__ */
1688 if(TimerBase != NULL)
1690 CloseDevice((struct IORequest *)&TimerRequest);
1691 TimerBase = NULL;
1694 #if defined(__amigaos4__)
1696 if(ISocket != NULL)
1698 DropInterface((struct Interface *)ISocket);
1699 ISocket = NULL;
1702 #endif /* __amigaos4__ */
1704 if(SocketBase != NULL)
1706 CloseLibrary(SocketBase);
1707 SocketBase = NULL;
1710 #if defined(__amigaos4__)
1712 if(IIcon != NULL)
1714 DropInterface((struct Interface *)IIcon);
1715 IIcon = NULL;
1718 #endif /* __amigaos4__ */
1720 if(IconBase != NULL)
1722 CloseLibrary(IconBase);
1723 IconBase = NULL;
1726 if(Locale != NULL)
1728 CloseLocale(Locale);
1729 Locale = NULL;
1732 #if defined(__amigaos4__)
1734 if(ILocale != NULL)
1736 DropInterface((struct Interface *)ILocale);
1737 ILocale = NULL;
1740 #endif /* __amigaos4__ */
1742 if(LocaleBase != NULL)
1744 CloseLibrary(LocaleBase);
1745 LocaleBase = NULL;
1748 if(MemoryPool != NULL)
1750 DeletePool(MemoryPool);
1751 MemoryPool = NULL;
1754 LEAVE();
1757 /****************************************************************************/
1759 /* Allocate all the necessary resources to get going. */
1760 STATIC BOOL
1761 Setup(
1762 STRPTR opt_password,
1763 BOOL opt_changecase,
1764 LONG * opt_time_zone_offset,
1765 LONG * opt_dst_offset,
1766 STRPTR translation_file)
1768 BOOL result = FALSE;
1769 int error = OK;
1770 LONG i;
1772 ENTER();
1774 NewList((struct List *)&FileList);
1775 NewList((struct List *)&LockList);
1777 MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC,4096,4096);
1778 if(MemoryPool == NULL)
1780 ReportError("Could not create memory pool.");
1781 goto out;
1784 LocaleBase = OpenLibrary("locale.library",38);
1786 #if defined(__amigaos4__)
1788 if(LocaleBase != NULL)
1790 ILocale = (struct LocaleIFace *)GetInterface(LocaleBase, "main", 1, 0);
1791 if(ILocale == NULL)
1793 CloseLibrary(LocaleBase);
1794 LocaleBase = NULL;
1798 #endif /* __amigaos4__ */
1800 if(LocaleBase != NULL)
1801 Locale = OpenLocale(NULL);
1803 if(opt_time_zone_offset != NULL)
1805 TimeZoneOffset = (*opt_time_zone_offset);
1806 OverrideLocaleTimeZone = TRUE;
1809 if(opt_dst_offset != NULL)
1810 DSTOffset = -60 * (*opt_dst_offset);
1812 memset(&TimerRequest,0,sizeof(TimerRequest));
1814 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest,0) != OK)
1816 ReportError("Could not open 'timer.device'.");
1817 goto out;
1820 TimerBase = (struct Library *)TimerRequest.tr_node.io_Device;
1822 #if defined(__amigaos4__)
1824 if(TimerBase != NULL)
1826 ITimer = (struct TimerIFace *)GetInterface(TimerBase, "main", 1, 0);
1827 if(ITimer == NULL)
1829 ReportError("Could not open 'timer.device'.");
1830 goto out;
1834 #endif /* __amigaos4__ */
1836 SocketBase = OpenLibrary("bsdsocket.library",3);
1838 #if defined(__amigaos4__)
1840 if(SocketBase != NULL)
1842 ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, 0);
1843 if(ISocket == NULL)
1845 CloseLibrary(SocketBase);
1846 SocketBase = NULL;
1850 #endif /* __amigaos4__ */
1852 if(SocketBase == NULL)
1854 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
1855 goto out;
1858 error = SocketBaseTags(
1859 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), &errno,
1860 SBTM_SETVAL(SBTC_HERRNOLONGPTR), &h_errno,
1861 SBTM_SETVAL(SBTC_LOGTAGPTR), HandlerName,
1862 SBTM_SETVAL(SBTC_BREAKMASK), SIGBREAKF_CTRL_C,
1863 TAG_END);
1864 if(error != OK)
1866 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
1867 goto out;
1870 if(opt_changecase)
1872 for(i = 0 ; i < (LONG)strlen(opt_password) ; i++)
1873 opt_password[i] = ToUpper(opt_password[i]);
1876 TranslateNames = FALSE;
1878 /* Read the translation file, if possible. */
1879 if(translation_file != NULL)
1881 STRPTR msg = NULL;
1882 BPTR file;
1884 error = OK;
1886 file = Open(translation_file,MODE_OLDFILE);
1887 if(file != ZERO)
1889 if(Read(file,A2M,256) != 256 ||
1890 Read(file,M2A,256) != 256)
1892 msg = "Could not read translation file";
1893 error = IoErr();
1896 Close(file);
1898 else
1900 msg = "Could not open translation file";
1901 error = IoErr();
1904 if(msg == NULL)
1906 TranslateNames = TRUE;
1908 else
1910 UBYTE description[100];
1912 Fault(error,NULL,description,sizeof(description));
1913 for(i = ((int)strlen(description)) - 1 ; i >= 0 ; i--)
1915 if(description[i] == '\n')
1916 description[i] = '\0';
1919 ReportError("%s '%s' (%ld, %s).",msg,translation_file,error,description);
1920 goto out;
1924 result = TRUE;
1926 out:
1928 RETURN(result);
1929 return(result);
1932 /****************************************************************************/
1935 /* Make connection to server and make a volume for it. */
1936 STATIC BOOL
1937 AddVolume(
1938 STRPTR device_name,
1939 STRPTR volume_name,
1940 STRPTR service,
1941 STRPTR workgroup,
1942 STRPTR username,
1943 STRPTR opt_password,
1944 STRPTR opt_clientname,
1945 STRPTR opt_servername,
1946 int opt_cachesize,
1947 int opt_max_transmit,
1948 BOOL opt_raw_smb)
1950 BOOL result = FALSE;
1951 struct DosList * dl;
1952 int error = OK;
1953 STRPTR actual_volume_name;
1954 LONG actual_volume_name_len;
1955 UBYTE name[MAX_FILENAME_LEN];
1956 BOOL device_exists = FALSE;
1957 LONG len,i;
1959 ENTER();
1961 error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,opt_max_transmit,opt_raw_smb,&ServerData);
1962 if(error < 0)
1963 goto out;
1965 /* If a device name was provided, check whether it is
1966 * well-formed.
1968 if(device_name != NULL)
1970 len = strlen(device_name);
1971 if(len > 255)
1972 len = 255;
1974 for(i = 0 ; i < len ; i++)
1976 if(device_name[i] == '/')
1978 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
1979 goto out;
1983 /* Lose any trailing colon characters. */
1984 for(i = len-1 ; i >= 0 ; i--)
1986 if(device_name[i] == ':')
1987 len = i;
1990 if(len == 0)
1992 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
1993 goto out;
1996 memcpy(name,device_name,len);
1997 name[len] = '\0';
1999 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2001 if(FindDosEntry(dl,name,LDF_DEVICES) != NULL)
2002 device_exists = TRUE;
2004 else
2006 dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2008 /* Find a unique device name. */
2009 for(i = 0 ; i < 100 ; i++)
2011 SPrintf(name,"SMBFS%ld",(long)i);
2013 device_exists = (BOOL)(FindDosEntry(dl,name,LDF_DEVICES) != NULL);
2014 if(NOT device_exists)
2016 device_name = name;
2017 break;
2022 if(device_exists)
2024 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2026 ReportError("Device name '%s:' is already taken.",device_name);
2027 goto out;
2030 /* Finally, create the device node. */
2031 DeviceNode = MakeDosEntry(name,DLT_DEVICE);
2032 if(DeviceNode == NULL)
2034 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2036 ReportError("Could not create device node.");
2037 goto out;
2040 DeviceNode->dol_Task = FileSystemPort;
2042 /* Examine the volume name; make sure that it is
2043 * well-formed.
2045 if(volume_name == NULL)
2046 actual_volume_name = device_name;
2047 else
2048 actual_volume_name = volume_name;
2050 actual_volume_name_len = strlen(actual_volume_name);
2051 if(actual_volume_name_len > 255)
2052 actual_volume_name_len = 255;
2054 for(i = 0 ; i < actual_volume_name_len ; i++)
2056 if(actual_volume_name[i] == '/')
2058 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2060 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2061 goto out;
2065 /* Lose any trailing colon characters. */
2066 for(i = actual_volume_name_len-1 ; i >= 0 ; i--)
2068 if(actual_volume_name[i] == ':')
2069 actual_volume_name_len = i;
2072 if(actual_volume_name_len == 0)
2074 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2076 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name);
2077 goto out;
2080 /* Now, finally, take care of the volume name. */
2081 memcpy(name,actual_volume_name,actual_volume_name_len);
2082 name[actual_volume_name_len] = '\0';
2084 VolumeNode = MakeDosEntry(name,DLT_VOLUME);
2085 if(VolumeNode == NULL)
2087 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2089 ReportError("Could not create volume node.");
2090 goto out;
2093 VolumeNode->dol_Task = FileSystemPort;
2094 DateStamp(&VolumeNode->dol_misc.dol_volume.dol_VolumeDate);
2095 VolumeNode->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
2097 if(DeviceNode != NULL)
2099 AddDosEntry(DeviceNode);
2101 DeviceNodeAdded = TRUE;
2104 /* Note: we always need the volume node to make some file
2105 * system operations safe (e.g. Lock()), but we may
2106 * not always need to make it visible.
2108 if(volume_name != NULL && VolumeNode != NULL)
2110 AddDosEntry(VolumeNode);
2112 VolumeNodeAdded = TRUE;
2115 /* And that concludes the mounting operation. */
2116 UnLockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
2118 /* Tell Workbench and friends to update their volume lists. */
2119 if(VolumeNodeAdded)
2120 SendDiskChange(IECLASS_DISKINSERTED);
2122 result = TRUE;
2124 out:
2126 RETURN(result);
2127 return(result);
2130 /****************************************************************************/
2132 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2133 INLINE STATIC VOID
2134 ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
2136 #ifdef AROS_FAST_BSTR
2137 strncpy(cstring, bstring, max_len);
2138 #else
2139 STRPTR from = bstring;
2140 LONG len = from[0];
2142 if(len > max_len-1)
2143 len = max_len-1;
2145 if(len > 0)
2146 memcpy(cstring,from+1,len);
2148 cstring[len] = '\0';
2149 #endif
2152 /* Convert a NUL terminated 'C' string into a BCPL string. */
2153 INLINE STATIC VOID
2154 ConvertCString(APTR bstring,LONG max_len,STRPTR cstring,LONG len)
2156 STRPTR to = bstring;
2158 if(len > max_len-1)
2159 len = max_len-1;
2161 (*to++) = len;
2162 memcpy(to,cstring,len);
2165 /****************************************************************************/
2167 /* Build the fully qualified name of a file or directory in reference
2168 * to the name of the parent directory. This takes care of all the
2169 * special cases, such as the root directory. The result will be converted
2170 * to be in a form suitable for use with the SMB file sharing service.
2172 STATIC LONG
2173 BuildFullName(
2174 STRPTR parent_name,
2175 STRPTR name,
2176 STRPTR * result_ptr,
2177 LONG * result_size_ptr)
2179 LONG error = OK;
2180 STRPTR buffer;
2181 LONG len,size;
2182 LONG i;
2184 ENTER();
2186 SHOWSTRING(parent_name);
2187 SHOWSTRING(name);
2189 (*result_ptr) = NULL;
2191 /* Throw everything left of the colon away. */
2192 if(name != NULL)
2194 for(i = 0 ; i < (LONG)strlen(name) ; i++)
2196 if(name[i] == ':')
2198 name = &name[i+1];
2199 break;
2204 /* Now, how much room is needed for the complete
2205 * path to fit into a buffer?
2207 len = 2;
2209 if(parent_name != NULL)
2210 len += strlen(parent_name) + 1;
2212 if(name != NULL)
2213 len += strlen(name) + 1;
2215 if(len < SMB_MAXNAMELEN)
2216 len = SMB_MAXNAMELEN;
2218 size = len + 3;
2220 buffer = AllocateMemory(size);
2221 if(buffer == NULL)
2223 error = ERROR_NO_FREE_STORE;
2224 goto out;
2227 /* Start by filling in the path name. */
2228 if(parent_name != NULL)
2230 /* Skip any excess separators. */
2231 while((*parent_name) == SMB_PATH_SEPARATOR)
2232 parent_name++;
2234 buffer[0] = SMB_PATH_SEPARATOR;
2235 strcpy(&buffer[1],parent_name);
2237 else
2239 strcpy(buffer,SMB_ROOT_DIR_NAME);
2242 /* If there's a name to add, do just that. */
2243 if(name != NULL)
2245 LONG segment_start;
2246 LONG segment_len;
2247 LONG buffer_len;
2248 LONG name_len;
2250 buffer_len = strlen(buffer);
2251 name_len = strlen(name);
2253 segment_start = 0;
2255 while(TRUE)
2257 segment_len = 0;
2259 /* Extract the next path name segment. */
2260 for(i = segment_start ; i <= name_len ; i++)
2262 if(i == name_len)
2264 segment_len = i - segment_start;
2265 break;
2267 else if (name[i] == '/')
2269 segment_len = i - segment_start + 1;
2270 break;
2274 /* We're finished if there are no further
2275 * path name segments to take care of.
2277 if(segment_len == 0)
2279 buffer[buffer_len] = '\0';
2280 break;
2283 /* A single slash indicates that we need to move up
2284 * to the parent directory, if any.
2286 if(segment_len == 1 && name[segment_start] == '/')
2288 /* Is this already the root directory name? */
2289 if(buffer_len <= 1)
2291 FreeMemory(buffer);
2292 buffer = NULL;
2294 goto out;
2296 else
2298 /* Skip the last path component. */
2299 for(i = 1 ; i <= buffer_len ; i++)
2301 if(i == buffer_len)
2303 /* We just skipped the first path
2304 * component following the root
2305 * directory name. We preserve
2306 * the first character since it
2307 * refers to the root directory.
2309 buffer_len = 1;
2310 break;
2312 else if (buffer[buffer_len-i] == SMB_PATH_SEPARATOR)
2314 /* This removes both the path separator and
2315 * the name following it.
2317 buffer_len -= i;
2318 break;
2323 else
2325 /* Add a proper separator character if
2326 * necessary.
2328 if(buffer_len > 0 && buffer[buffer_len-1] != SMB_PATH_SEPARATOR)
2329 buffer[buffer_len++] = SMB_PATH_SEPARATOR;
2331 /* Find out how many characters are in that name; this
2332 * excludes the terminating slash.
2334 if(name[segment_start + segment_len - 1] == '/')
2335 len = segment_len - 1;
2336 else
2337 len = segment_len;
2339 memcpy(&buffer[buffer_len],&name[segment_start],len);
2340 buffer_len += len;
2343 segment_start += segment_len;
2347 (*result_ptr) = buffer;
2348 (*result_size_ptr) = size;
2350 SHOWSTRING(buffer);
2352 out:
2354 if(error != OK)
2355 FreeMemory(buffer);
2357 RETURN(error);
2358 return(error);
2361 /****************************************************************************/
2363 STATIC BOOL
2364 Action_Startup(
2365 struct FileSysStartupMsg * fssm,
2366 struct DosList * device_node,
2367 SIPTR * error_ptr)
2369 LONG cache_size = 0;
2370 LONG max_transmit = -1;
2371 char env_workgroup_name[17];
2372 char env_user_name[64];
2373 char env_password[64];
2375 UBYTE *control;
2376 char env_service_name[17];
2378 BOOL result = DOSTRUE;
2379 LONG error = 0;
2381 ENTER();
2383 DeviceNode = device_node;
2384 device_node->dol_Task = FileSystemPort;
2386 memset(&args,0,sizeof(args));
2388 Parameters = AllocDosObject(DOS_RDARGS, NULL);
2389 if(Parameters == NULL)
2390 goto out;
2391 control = (UBYTE *)
2392 ((struct DosEnvec *)BADDR(fssm->fssm_Environ))->de_Control;
2393 Parameters->RDA_Source.CS_Buffer = control;
2394 Parameters->RDA_Source.CS_Length = strlen(control);
2395 Parameters = ReadArgs(cmd_template,(IPTR *)&args,Parameters);
2396 if(Parameters == NULL)
2398 goto out;
2401 if(args.Workgroup == NULL)
2403 if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
2404 GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
2406 args.Workgroup = env_workgroup_name;
2408 else
2410 args.Workgroup = "WORKGROUP";
2414 if(args.UserName == NULL)
2416 if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
2417 GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
2419 args.UserName = env_user_name;
2423 if(args.Password == NULL)
2425 if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
2426 args.Password = env_password;
2429 if(args.Service == NULL)
2431 if(GetVar("smbfs_service",env_service_name,sizeof(env_service_name),0) > 0 ||
2432 GetVar("smbfs_share",env_service_name,sizeof(env_service_name),0) > 0)
2434 args.Service = env_service_name;
2436 else
2438 ReportError("Required 'SERVICE' parameter was not provided.");
2439 goto out;
2443 if(args.CacheSize != NULL)
2444 cache_size = (*args.CacheSize);
2446 if(args.MaxTransmit != NULL)
2447 max_transmit = (*args.MaxTransmit);
2449 /* Use the default if no user name is given. */
2450 if(args.UserName == NULL)
2451 args.UserName = "GUEST";
2453 /* Volume name defaults to share name. */
2454 if(args.VolumeName == NULL)
2455 args.VolumeName = FilePart(args.Service);
2457 /* Use the default if no device or volume name is given. */
2458 if(args.DeviceName == NULL && args.VolumeName == NULL)
2459 args.DeviceName = "SMBFS";
2461 /* UTF8 file name translation disables code-page based translation. */
2462 if(args.UTF8)
2463 args.TranslationFile = NULL;
2465 CaseSensitive = (BOOL)args.CaseSensitive;
2466 OmitHidden = (BOOL)args.OmitHidden;
2467 TranslateUTF8 = (BOOL)args.UTF8;
2469 /* Configure the debugging options. */
2470 if(args.DebugLevel != NULL)
2471 SETDEBUGLEVEL(*args.DebugLevel);
2472 else
2473 SETDEBUGLEVEL(0);
2475 /* Enable SMB packet decoding, but only if not started from Workbench. */
2476 #if defined(DUMP_SMB)
2478 if(args.DumpSMB)
2479 control_smb_dump(TRUE);
2481 #endif /* DUMP_SMB */
2483 D(("%s (%s)",VERS,DATE));
2485 if(Setup(
2486 args.Password,
2487 args.ChangeCase,
2488 args.TimeZoneOffset,
2489 args.DSTOffset,
2490 args.TranslationFile))
2492 AddVolume(
2493 args.DeviceName,
2494 args.VolumeName,
2495 args.Service,
2496 args.Workgroup,
2497 args.UserName,
2498 args.Password,
2499 args.ClientName,
2500 args.ServerName,
2501 cache_size,
2502 max_transmit,
2503 !args.NetBIOSTransport /* Use raw SMB transport instead of NetBIOS transport? */
2506 else
2508 result = FALSE;
2511 out:
2513 (*error_ptr) = error;
2515 RETURN(result);
2516 return(result);
2519 /****************************************************************************/
2521 STATIC BPTR
2522 Action_Parent(
2523 struct FileLock * parent,
2524 SIPTR * error_ptr)
2526 BPTR result = ZERO;
2527 STRPTR full_name = NULL;
2528 LONG full_name_size;
2529 STRPTR parent_name;
2530 BOOL cleanup = TRUE;
2531 struct LockNode * ln = NULL;
2532 LONG error;
2534 ENTER();
2536 SHOWVALUE(parent);
2538 if(parent != NULL)
2540 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2542 parent_name = parent_ln->ln_FullName;
2544 else
2546 parent_name = NULL;
2549 error = BuildFullName(parent_name,"/",&full_name,&full_name_size);
2550 if(error != OK)
2551 goto out;
2553 /* Check if we ended up having to return the parent of
2554 * the root directory. This is indicated by a NULL
2555 * name pointer and a zero error code.
2557 if(full_name == NULL)
2558 goto out;
2560 ln = AllocateMemory(sizeof(*ln));
2561 if(ln == NULL)
2563 error = ERROR_NO_FREE_STORE;
2564 goto out;
2567 memset(ln,0,sizeof(*ln));
2569 ln->ln_FileLock.fl_Key = (IPTR)ln;
2570 ln->ln_FileLock.fl_Access = SHARED_LOCK;
2571 ln->ln_FileLock.fl_Task = FileSystemPort;
2572 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
2573 ln->ln_FullName = full_name;
2575 SHOWSTRING(full_name);
2577 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2578 if(error < 0)
2580 error = MapErrnoToIoErr(error);
2581 goto out;
2584 AddTail((struct List *)&LockList,(struct Node *)ln);
2585 result = MKBADDR(&ln->ln_FileLock);
2586 cleanup = FALSE;
2587 SHOWVALUE(&ln->ln_FileLock);
2589 out:
2591 if(cleanup)
2593 FreeMemory(full_name);
2594 FreeMemory(ln);
2597 (*error_ptr) = error;
2599 RETURN(result);
2600 return(result);
2603 /****************************************************************************/
2605 /* Find the lock node corresponding to a given name,
2606 * starting from node start. (if node, this one is skipped)
2608 STATIC struct LockNode *
2609 FindNextLockNode(STRPTR name,struct LockNode * last_ln)
2611 struct LockNode * result = NULL;
2612 struct LockNode * ln;
2613 struct LockNode * start;
2615 if(last_ln != NULL)
2616 start = (struct LockNode *)last_ln->ln_MinNode.mln_Succ;
2617 else
2618 start = (struct LockNode *)LockList.mlh_Head;
2620 for(ln = start ;
2621 ln->ln_MinNode.mln_Succ != NULL ;
2622 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
2624 if(CompareNames(name,ln->ln_FullName) == SAME)
2626 result = ln;
2627 break;
2631 return(result);
2634 /****************************************************************************/
2636 STATIC LONG
2637 Action_DeleteObject(
2638 struct FileLock * parent,
2639 APTR bcpl_name,
2640 SIPTR * error_ptr)
2642 LONG result = DOSFALSE;
2643 STRPTR full_name = NULL;
2644 LONG full_name_size;
2645 smba_file_t * file = NULL;
2646 STRPTR parent_name;
2647 STRPTR full_parent_name = NULL;
2648 UBYTE name[MAX_FILENAME_LEN];
2649 struct LockNode * ln;
2650 smba_stat_t st;
2651 LONG error;
2653 ENTER();
2655 if(WriteProtected)
2657 error = ERROR_DISK_WRITE_PROTECTED;
2658 goto out;
2661 SHOWVALUE(parent);
2663 if(parent != NULL)
2665 ln = (struct LockNode *)parent->fl_Key;
2667 parent_name = ln->ln_FullName;
2669 else
2671 parent_name = NULL;
2674 /* Name string, as given in the DOS packet, is in
2675 * BCPL format and needs to be converted into
2676 * 'C' format.
2678 ConvertBString(sizeof(name),name,bcpl_name);
2680 /* Translate the Amiga file name into UTF-8 encoded form? */
2681 if (TranslateUTF8)
2683 UBYTE encoded_name[MAX_FILENAME_LEN];
2684 int encoded_name_len;
2685 LONG name_len = strlen(name);
2687 /* Figure out how long the UTF-8 version will become. */
2688 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
2690 /* Encoding error occured, or the resulting name is longer than the buffer will hold? */
2691 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
2693 error = ERROR_INVALID_COMPONENT_NAME;
2694 goto out;
2697 /* Repeat the encoding process, writing the result to the
2698 * replacement name buffer now.
2700 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
2702 /* Copy it back to the conversion buffer (which is not terribly efficient, though). */
2703 strlcpy(name,encoded_name,sizeof(name));
2705 /* Translate the Amiga file name using a translation table? */
2706 else if (TranslateNames)
2708 TranslateCName(name,A2M);
2711 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2712 if(error != OK)
2713 goto out;
2715 /* Trying to delete the root directory, are you kidding? */
2716 if(full_name == NULL)
2718 error = ERROR_OBJECT_WRONG_TYPE;
2719 goto out;
2722 /* We need to find this file's parent directory, so that
2723 * in case the directory contents are currently being
2724 * examined, that process is restarted.
2726 full_parent_name = AllocateMemory(strlen(full_name)+3);
2727 if(full_parent_name == NULL)
2729 error = ERROR_NO_FREE_STORE;
2730 goto out;
2733 strcpy(full_parent_name,full_name);
2735 /* Build the parent object name - Piru */
2736 if (full_parent_name[0] != '\0')
2738 int i;
2740 i = strlen(full_parent_name) - 1;
2741 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2742 i--;
2744 for ( ; i >= 0 ; i--)
2746 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2748 full_parent_name[i] = '\0';
2749 break;
2754 /* NOTE: Mark all locks to this object as restart, not just first
2755 one - Piru */
2756 ln = NULL;
2757 while ((ln = FindNextLockNode(full_parent_name, ln)) != NULL)
2758 ln->ln_RestartExamine = TRUE;
2760 ln = FindLockNode(full_parent_name,NULL);
2761 if(ln != NULL)
2762 ln->ln_RestartExamine = TRUE;
2764 FreeMemory(full_parent_name);
2765 full_parent_name = NULL;
2767 SHOWSTRING(full_name);
2769 error = smba_open(ServerData,full_name,full_name_size,&file);
2770 if(error < 0)
2772 error = MapErrnoToIoErr(error);
2773 goto out;
2776 error = smba_getattr(file,&st);
2777 if(error < 0)
2779 error = MapErrnoToIoErr(error);
2780 goto out;
2783 smba_close(file);
2784 file = NULL;
2786 if(st.is_dir)
2788 SHOWMSG("removing a directory");
2790 error = smba_rmdir(ServerData,full_name);
2791 if(error < 0)
2793 SHOWVALUE(error);
2795 /* This is a little bit difficult to justify since
2796 * the error code may indicate a different cause,
2797 * but in practice 'EACCES' seems to be returned
2798 * if the directory to remove is not empty.
2800 if(error == (-EACCES))
2801 error = ERROR_DIRECTORY_NOT_EMPTY;
2802 else
2803 error = MapErrnoToIoErr(error);
2805 goto out;
2808 else
2810 SHOWMSG("removing a file");
2812 error = smba_remove(ServerData,full_name);
2813 if(error < 0)
2815 SHOWVALUE(error);
2817 error = MapErrnoToIoErr(error);
2818 goto out;
2822 SHOWMSG("done.");
2824 result = DOSTRUE;
2826 out:
2828 FreeMemory(full_name);
2829 FreeMemory(full_parent_name);
2831 if(file != NULL)
2832 smba_close(file);
2834 (*error_ptr) = error;
2836 RETURN(result);
2837 return(result);
2840 /****************************************************************************/
2842 STATIC BPTR
2843 Action_CreateDir(
2844 struct FileLock * parent,
2845 APTR bcpl_name,
2846 SIPTR * error_ptr)
2848 BPTR result = ZERO;
2849 STRPTR full_name = NULL;
2850 LONG full_name_size;
2851 struct LockNode * ln = NULL;
2852 STRPTR parent_name;
2853 STRPTR dir_name = NULL;
2854 smba_file_t * dir = NULL;
2855 STRPTR base_name;
2856 UBYTE name[MAX_FILENAME_LEN];
2857 LONG error;
2858 LONG i;
2860 ENTER();
2862 if(WriteProtected)
2864 error = ERROR_DISK_WRITE_PROTECTED;
2865 goto out;
2868 SHOWVALUE(parent);
2870 if(parent != NULL)
2872 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2874 parent_name = parent_ln->ln_FullName;
2876 else
2878 parent_name = NULL;
2881 ConvertBString(sizeof(name),name,bcpl_name);
2883 if (TranslateUTF8)
2885 UBYTE encoded_name[MAX_FILENAME_LEN];
2886 int encoded_name_len;
2887 LONG name_len = strlen(name);
2889 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
2890 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
2892 error = ERROR_INVALID_COMPONENT_NAME;
2893 goto out;
2896 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
2898 strlcpy(name,encoded_name,sizeof(name));
2900 else if (TranslateNames)
2902 TranslateCName(name,A2M);
2905 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2906 if(error != OK)
2907 goto out;
2909 /* Trying to overwrite the root directory, are you kidding? */
2910 if(full_name == NULL)
2912 error = ERROR_OBJECT_IN_USE;
2913 goto out;
2916 dir_name = AllocateMemory(strlen(full_name)+3);
2917 if(dir_name == NULL)
2919 error = ERROR_NO_FREE_STORE;
2920 goto out;
2923 strcpy(dir_name,full_name);
2924 base_name = NULL;
2925 for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
2927 if(dir_name[i] == SMB_PATH_SEPARATOR)
2929 if(i == 0)
2931 memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1);
2932 i++;
2935 dir_name[i] = '\0';
2937 base_name = &dir_name[i+1];
2938 break;
2942 ln = AllocateMemory(sizeof(*ln));
2943 if(ln == NULL)
2945 error = ERROR_NO_FREE_STORE;
2946 goto out;
2949 memset(ln,0,sizeof(*ln));
2951 ln->ln_FileLock.fl_Key = (IPTR)ln;
2952 ln->ln_FileLock.fl_Access = EXCLUSIVE_LOCK;
2953 ln->ln_FileLock.fl_Task = FileSystemPort;
2954 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
2955 ln->ln_FullName = full_name;
2957 error = smba_open(ServerData,dir_name,strlen(full_name)+3,&dir);
2958 if(error < 0)
2960 error = MapErrnoToIoErr(error);
2961 goto out;
2964 error = smba_mkdir(dir,base_name);
2965 if(error < 0)
2967 error = MapErrnoToIoErr(error);
2968 goto out;
2971 smba_close(dir);
2972 dir = NULL;
2974 SHOWSTRING(full_name);
2976 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2977 if(error < 0)
2979 error = MapErrnoToIoErr(error);
2980 goto out;
2983 AddTail((struct List *)&LockList,(struct Node *)ln);
2984 result = MKBADDR(&ln->ln_FileLock);
2985 SHOWVALUE(&ln->ln_FileLock);
2987 out:
2989 if(dir != NULL)
2990 smba_close(dir);
2992 FreeMemory(dir_name);
2994 if(result == ZERO)
2996 FreeMemory(full_name);
2997 FreeMemory(ln);
3000 (*error_ptr) = error;
3002 RETURN(result);
3003 return(result);
3006 /****************************************************************************/
3008 STATIC BPTR
3009 Action_LocateObject(
3010 struct FileLock * parent,
3011 APTR bcpl_name,
3012 LONG mode,
3013 SIPTR * error_ptr)
3015 BPTR result = ZERO;
3016 STRPTR full_name = NULL;
3017 LONG full_name_size;
3018 struct LockNode * ln = NULL;
3019 STRPTR parent_name;
3020 UBYTE name[MAX_FILENAME_LEN];
3021 LONG error;
3023 ENTER();
3025 SHOWVALUE(parent);
3027 if(parent != NULL)
3029 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
3031 parent_name = parent_ln->ln_FullName;
3033 else
3035 parent_name = NULL;
3038 ConvertBString(sizeof(name),name,bcpl_name);
3040 if (TranslateUTF8)
3042 UBYTE encoded_name[MAX_FILENAME_LEN];
3043 int encoded_name_len;
3044 LONG name_len = strlen(name);
3046 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3047 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3049 error = ERROR_INVALID_COMPONENT_NAME;
3050 goto out;
3053 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3055 strlcpy(name,encoded_name,sizeof(name));
3057 else if (TranslateNames)
3059 TranslateCName(name,A2M);
3062 if(IsReservedName(FilePart(name)))
3064 error = ERROR_OBJECT_NOT_FOUND;
3065 goto out;
3068 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3069 if(error != OK)
3070 goto out;
3072 /* Trying to get a lock on the root directory's parent?
3073 * My pleasure.
3075 if(full_name == NULL)
3076 goto out;
3078 ln = AllocateMemory(sizeof(*ln));
3079 if(ln == NULL)
3081 error = ERROR_NO_FREE_STORE;
3082 goto out;
3085 memset(ln,0,sizeof(*ln));
3087 ln->ln_FileLock.fl_Key = (IPTR)ln;
3088 ln->ln_FileLock.fl_Access = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK;
3089 ln->ln_FileLock.fl_Task = FileSystemPort;
3090 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3091 ln->ln_FullName = full_name;
3093 error = CheckAccessModeCollision(full_name,ln->ln_FileLock.fl_Access);
3094 if(error != OK)
3095 goto out;
3097 SHOWSTRING(full_name);
3099 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3100 if(error < 0)
3102 error = MapErrnoToIoErr(error);
3103 goto out;
3106 AddTail((struct List *)&LockList,(struct Node *)ln);
3107 result = MKBADDR(&ln->ln_FileLock);
3108 SHOWVALUE(&ln->ln_FileLock);
3110 out:
3112 if(result == ZERO)
3114 FreeMemory(full_name);
3115 FreeMemory(ln);
3118 (*error_ptr) = error;
3120 RETURN(result);
3121 return(result);
3124 /****************************************************************************/
3126 STATIC BPTR
3127 Action_CopyDir(
3128 struct FileLock * lock,
3129 SIPTR * error_ptr)
3131 BPTR result = ZERO;
3132 STRPTR full_name = NULL;
3133 LONG full_name_size;
3134 struct LockNode * ln = NULL;
3135 STRPTR source_name;
3136 LONG source_mode;
3137 LONG error;
3139 ENTER();
3141 SHOWVALUE(lock);
3143 if(lock != NULL && lock->fl_Access != SHARED_LOCK)
3145 SHOWMSG("cannot duplicate exclusive lock");
3146 error = ERROR_OBJECT_IN_USE;
3147 goto out;
3150 ln = AllocateMemory(sizeof(*ln));
3151 if(ln == NULL)
3153 error = ERROR_NO_FREE_STORE;
3154 goto out;
3157 memset(ln,0,sizeof(*ln));
3159 if(lock != NULL)
3161 struct LockNode * source = (struct LockNode *)lock->fl_Key;
3163 source_name = source->ln_FullName;
3164 source_mode = source->ln_FileLock.fl_Access;
3166 else
3168 source_name = SMB_ROOT_DIR_NAME;
3169 source_mode = SHARED_LOCK;
3172 full_name_size = strlen(source_name)+3;
3173 if(full_name_size < SMB_MAXNAMELEN+1)
3174 full_name_size = SMB_MAXNAMELEN+1;
3176 full_name = AllocateMemory(full_name_size);
3177 if(full_name == NULL)
3179 error = ERROR_NO_FREE_STORE;
3180 goto out;
3183 strcpy(full_name,source_name);
3185 ln->ln_FileLock.fl_Key = (IPTR)ln;
3186 ln->ln_FileLock.fl_Access = source_mode;
3187 ln->ln_FileLock.fl_Task = FileSystemPort;
3188 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
3189 ln->ln_FullName = full_name;
3191 SHOWSTRING(full_name);
3193 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
3194 if(error < 0)
3196 error = MapErrnoToIoErr(error);
3197 goto out;
3200 AddTail((struct List *)&LockList,(struct Node *)ln);
3201 result = MKBADDR(&ln->ln_FileLock);
3202 SHOWVALUE(&ln->ln_FileLock);
3204 out:
3206 if(result == ZERO)
3208 FreeMemory(full_name);
3209 FreeMemory(ln);
3212 (*error_ptr) = error;
3214 RETURN(result);
3215 return(result);
3218 /****************************************************************************/
3220 STATIC LONG
3221 Action_FreeLock(
3222 struct FileLock * lock,
3223 SIPTR * error_ptr)
3225 LONG result = DOSTRUE;
3226 struct LockNode * ln;
3227 LONG error = OK;
3229 ENTER();
3231 SHOWVALUE(lock);
3233 if(lock == NULL)
3234 goto out;
3236 ln = (struct LockNode *)lock->fl_Key;
3238 Remove((struct Node *)ln);
3240 smba_close(ln->ln_File);
3241 FreeMemory(ln->ln_FullName);
3242 FreeMemory(ln);
3244 out:
3246 (*error_ptr) = error;
3248 RETURN(result);
3249 return(result);
3252 /****************************************************************************/
3254 STATIC LONG
3255 Action_SameLock(
3256 struct FileLock * lock1,
3257 struct FileLock * lock2,
3258 SIPTR * error_ptr)
3260 LONG result = DOSFALSE;
3261 STRPTR name1;
3262 STRPTR name2;
3263 LONG error = OK;
3265 ENTER();
3267 SHOWVALUE(lock1);
3268 SHOWVALUE(lock2);
3270 if(lock1 != NULL)
3272 struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
3274 name1 = ln->ln_FullName;
3276 else
3278 name1 = SMB_ROOT_DIR_NAME;
3281 if(lock2 != NULL)
3283 struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
3285 name2 = ln->ln_FullName;
3287 else
3289 name2 = SMB_ROOT_DIR_NAME;
3292 SHOWSTRING(name1);
3293 SHOWSTRING(name2);
3295 if(Stricmp(name1,name2) == SAME)
3296 result = DOSTRUE;
3298 (*error_ptr) = error;
3300 RETURN(result);
3301 return(result);
3304 /****************************************************************************/
3306 STATIC LONG
3307 Action_SetProtect(
3308 struct FileLock * parent,
3309 APTR bcpl_name,
3310 LONG mask,
3311 SIPTR * error_ptr)
3313 LONG result = DOSFALSE;
3314 STRPTR full_name = NULL;
3315 LONG full_name_size;
3316 smba_file_t * file = NULL;
3317 STRPTR parent_name;
3318 UBYTE name[MAX_FILENAME_LEN];
3319 smba_stat_t st;
3320 LONG error;
3322 ENTER();
3324 if(WriteProtected)
3326 error = ERROR_DISK_WRITE_PROTECTED;
3327 goto out;
3330 SHOWVALUE(parent);
3332 if(parent != NULL)
3334 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
3336 parent_name = ln->ln_FullName;
3338 else
3340 parent_name = NULL;
3343 ConvertBString(sizeof(name),name,bcpl_name);
3345 if (TranslateUTF8)
3347 UBYTE encoded_name[MAX_FILENAME_LEN];
3348 int encoded_name_len;
3349 LONG name_len = strlen(name);
3351 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3352 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3354 error = ERROR_INVALID_COMPONENT_NAME;
3355 goto out;
3358 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3360 strlcpy(name,encoded_name,sizeof(name));
3362 else if (TranslateNames)
3364 TranslateCName(name,A2M);
3367 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3368 if(error != OK)
3369 goto out;
3371 /* Trying to change the protection bits of the root
3372 * directory, are you kidding?
3374 if(full_name == NULL)
3376 error = ERROR_OBJECT_WRONG_TYPE;
3377 goto out;
3380 SHOWSTRING(full_name);
3382 error = smba_open(ServerData,full_name,full_name_size,&file);
3383 if(error < 0)
3385 error = MapErrnoToIoErr(error);
3386 goto out;
3389 memset(&st,0,sizeof(st));
3391 mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
3393 st.atime = -1;
3394 st.ctime = -1;
3395 st.mtime = -1;
3396 st.size = -1;
3398 if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
3400 SHOWMSG("write protection enabled");
3401 st.is_wp = TRUE;
3403 else
3405 SHOWMSG("write protection disabled");
3408 /* Careful: the 'archive' attribute has exactly the opposite
3409 * meaning in the Amiga and the SMB worlds.
3411 st.is_archive = ((mask & FIBF_ARCHIVE) == 0);
3413 /* The 'system' attribute is associated with the 'pure' bit for now. */
3414 st.is_system = ((mask & FIBF_PURE) != 0);
3416 error = smba_setattr(file,&st);
3417 if(error < 0)
3419 error = MapErrnoToIoErr(error);
3420 goto out;
3423 result = DOSTRUE;
3425 out:
3427 FreeMemory(full_name);
3429 if(file != NULL)
3430 smba_close(file);
3432 (*error_ptr) = error;
3434 RETURN(result);
3435 return(result);
3438 /****************************************************************************/
3440 STATIC LONG
3441 Action_RenameObject(
3442 struct FileLock * source_lock,
3443 APTR source_bcpl_name,
3444 struct FileLock * destination_lock,
3445 APTR destination_bcpl_name,
3446 SIPTR * error_ptr)
3448 struct LockNode * ln;
3449 LONG result = DOSFALSE;
3450 STRPTR full_source_name = NULL;
3451 LONG full_source_name_size;
3452 STRPTR full_destination_name = NULL;
3453 LONG full_destination_name_size;
3454 UBYTE name[MAX_FILENAME_LEN];
3455 STRPTR parent_name;
3456 LONG error;
3458 ENTER();
3460 if(WriteProtected)
3462 error = ERROR_DISK_WRITE_PROTECTED;
3463 goto out;
3466 SHOWVALUE(source_lock);
3467 SHOWVALUE(destination_lock);
3469 if(source_lock != NULL)
3471 ln = (struct LockNode *)source_lock->fl_Key;
3473 parent_name = ln->ln_FullName;
3475 else
3477 parent_name = NULL;
3480 ConvertBString(sizeof(name),name,source_bcpl_name);
3482 if (TranslateUTF8)
3484 UBYTE encoded_name[MAX_FILENAME_LEN];
3485 int encoded_name_len;
3486 LONG name_len = strlen(name);
3488 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3489 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3491 error = ERROR_INVALID_COMPONENT_NAME;
3492 goto out;
3495 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3497 strlcpy(name,encoded_name,sizeof(name));
3499 else if (TranslateNames)
3501 TranslateCName(name,A2M);
3504 error = BuildFullName(parent_name,name,&full_source_name,&full_source_name_size);
3505 if(error != OK)
3506 goto out;
3508 /* Trying to rename the root directory, are you kidding? */
3509 if(full_source_name == NULL)
3511 error = ERROR_OBJECT_IN_USE;
3512 goto out;
3515 if(destination_lock != NULL)
3517 ln = (struct LockNode *)destination_lock->fl_Key;
3519 parent_name = ln->ln_FullName;
3521 else
3523 parent_name = NULL;
3526 ConvertBString(sizeof(name),name,destination_bcpl_name);
3528 if (TranslateUTF8)
3530 UBYTE encoded_name[MAX_FILENAME_LEN];
3531 int encoded_name_len;
3532 LONG name_len = strlen(name);
3534 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
3535 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
3537 error = ERROR_INVALID_COMPONENT_NAME;
3538 goto out;
3541 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
3543 strlcpy(name,encoded_name,sizeof(name));
3545 else if (TranslateNames)
3547 TranslateCName(name,A2M);
3550 error = BuildFullName(parent_name,name,&full_destination_name,&full_destination_name_size);
3551 if(error != OK)
3552 goto out;
3554 /* Trying to rename the root directory, are you kidding? */
3555 if(full_destination_name == NULL)
3557 error = ERROR_OBJECT_IN_USE;
3558 goto out;
3561 error = NameAlreadyInUse(full_source_name);
3562 if(error != OK)
3563 goto out;
3565 error = NameAlreadyInUse(full_destination_name);
3566 if(error != OK)
3567 goto out;
3569 SHOWSTRING(full_source_name);
3570 SHOWSTRING(full_destination_name);
3572 error = smba_rename(ServerData,full_source_name,full_destination_name);
3573 if(error < 0)
3575 error = MapErrnoToIoErr(error);
3576 goto out;
3579 result = DOSTRUE;
3581 out:
3583 FreeMemory(full_source_name);
3584 FreeMemory(full_destination_name);
3586 (*error_ptr) = error;
3588 RETURN(result);
3589 return(result);
3592 /****************************************************************************/
3594 STATIC LONG
3595 Action_DiskInfo(
3596 struct InfoData * id,
3597 SIPTR * error_ptr)
3599 LONG result = DOSTRUE;
3600 long block_size;
3601 long num_blocks;
3602 long num_blocks_free;
3603 LONG error;
3605 ENTER();
3607 memset(id,0,sizeof(*id));
3609 if(WriteProtected)
3610 id->id_DiskState = ID_WRITE_PROTECTED;
3611 else
3612 id->id_DiskState = ID_VALIDATED;
3614 error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
3615 if(error >= 0)
3617 SHOWMSG("got the disk data");
3618 SHOWVALUE(block_size);
3619 SHOWVALUE(num_blocks);
3620 SHOWVALUE(num_blocks_free);
3622 if(block_size <= 0)
3623 block_size = 512;
3625 if(block_size < 512)
3627 num_blocks /= (512 / block_size);
3628 num_blocks_free /= (512 / block_size);
3630 else if (block_size > 512)
3632 num_blocks *= (block_size / 512);
3633 num_blocks_free *= (block_size / 512);
3636 id->id_NumBlocks = num_blocks;
3637 id->id_NumBlocksUsed = num_blocks - num_blocks_free;
3638 id->id_BytesPerBlock = 512;
3639 id->id_DiskType = ID_DOS_DISK;
3640 id->id_VolumeNode = MKBADDR(VolumeNode);
3641 id->id_InUse = NOT (IsListEmpty(&FileList) && IsListEmpty(&LockList));
3643 if(id->id_NumBlocks == 0)
3644 id->id_NumBlocks = 1;
3646 if(id->id_NumBlocksUsed == 0)
3647 id->id_NumBlocksUsed = 1;
3649 else
3651 SHOWMSG("could not get any disk data");
3653 id->id_NumBlocks = 1;
3654 id->id_NumBlocksUsed = 1;
3655 id->id_BytesPerBlock = 512;
3656 id->id_DiskType = ID_NO_DISK_PRESENT;
3658 error = MapErrnoToIoErr(error);
3659 result = DOSFALSE;
3662 SHOWVALUE(id->id_NumBlocks);
3663 SHOWVALUE(id->id_NumBlocksUsed);
3664 SHOWVALUE(id->id_BytesPerBlock);
3665 SHOWVALUE(id->id_DiskType);
3666 SHOWVALUE(id->id_VolumeNode);
3667 SHOWVALUE(id->id_InUse);
3669 (*error_ptr) = error;
3671 RETURN(result);
3672 return(result);
3675 STATIC LONG
3676 Action_Info(
3677 struct FileLock * lock,
3678 struct InfoData * id,
3679 SIPTR * error_ptr)
3681 LONG result;
3683 ENTER();
3685 SHOWVALUE(lock);
3687 /* We need to check if the lock matches the volume node. However,
3688 * a NULL lock is valid, too.
3690 if(lock != NULL && lock->fl_Volume != MKBADDR(VolumeNode))
3692 SHOWMSG("volume node does not match");
3694 result = DOSFALSE;
3696 (*error_ptr) = ERROR_NO_DISK;
3698 else
3700 result = Action_DiskInfo(id,error_ptr);
3703 RETURN(result);
3704 return(result);
3707 /****************************************************************************/
3709 STATIC LONG
3710 Action_ExamineObject(
3711 struct FileLock * lock,
3712 struct FileInfoBlock * fib,
3713 SIPTR * error_ptr)
3715 LONG result = DOSFALSE;
3716 LONG error = OK;
3718 ENTER();
3720 SHOWVALUE(lock);
3722 memset(fib,0,sizeof(*fib));
3724 if(lock == NULL)
3726 #if !defined(__AROS__)
3727 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3728 LONG len = volume_name[0];
3730 memcpy(fib->fib_FileName+1,volume_name+1,len);
3731 fib->fib_FileName[0] = len;
3732 #else
3733 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3734 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3736 memcpy(fib->fib_FileName + 1, volume_name, len);
3737 fib->fib_FileName[0] = len;
3738 #endif
3739 SHOWMSG("ZERO root lock");
3741 fib->fib_DirEntryType = ST_ROOT;
3742 fib->fib_EntryType = ST_ROOT;
3743 fib->fib_NumBlocks = 1;
3744 fib->fib_Date = VolumeNode->dol_misc.dol_volume.dol_VolumeDate;
3745 fib->fib_DiskKey = -1;
3746 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3747 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3749 else
3751 struct LockNode * ln = (struct LockNode *)lock->fl_Key;
3752 LONG seconds;
3753 smba_stat_t st;
3755 error = smba_getattr(ln->ln_File,&st);
3756 if(error < 0)
3758 SHOWMSG("information not available");
3760 error = MapErrnoToIoErr(error);
3761 goto out;
3764 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3765 if(seconds < 0)
3766 seconds = 0;
3768 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
3769 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
3770 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
3772 SHOWSTRING(ln->ln_FullName);
3774 if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME)
3776 #if !defined(__AROS__)
3777 STRPTR volume_name = BADDR(VolumeNode->dol_Name);
3778 LONG len = volume_name[0];
3780 memcpy(fib->fib_FileName+1,volume_name+1,len);
3781 fib->fib_FileName[0] = len;
3782 #else
3783 STRPTR volume_name = AROS_BSTR_ADDR(VolumeNode->dol_Name);
3784 LONG len = AROS_BSTR_strlen(VolumeNode->dol_Name);
3786 memcpy(fib->fib_FileName + 1, volume_name, len);
3787 fib->fib_FileName[0] = len;
3788 #endif
3789 SHOWMSG("root lock");
3791 fib->fib_DirEntryType = ST_ROOT;
3792 fib->fib_EntryType = ST_ROOT;
3793 fib->fib_NumBlocks = 1;
3794 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3795 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3797 else
3799 STRPTR name;
3800 LONG name_len;
3801 LONG i;
3803 name = ln->ln_FullName;
3804 name_len = strlen(name);
3806 for(i = name_len-1 ; i >= 0 ; i--)
3808 if(name[i] == SMB_PATH_SEPARATOR)
3810 name = &name[i+1];
3811 break;
3815 /* Just checking: will the name fit? */
3816 if(name_len >= sizeof(fib->fib_FileName))
3818 error = ERROR_INVALID_COMPONENT_NAME;
3819 goto out;
3822 /* Translate the name of the file/directory from UTF-8
3823 * into AmigaOS ISO 8859-1 (ISO Latin 1) encoding?
3825 if(TranslateUTF8)
3827 UBYTE decoded_name[MAX_FILENAME_LEN];
3828 int decoded_name_len;
3830 /* Try to decode the file file, translating it into ISO 8859-1 format. */
3831 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
3833 /* Decoding error occured, or the decoded name would be longer than
3834 * buffer would allow?
3836 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
3838 error = ERROR_INVALID_COMPONENT_NAME;
3839 goto out;
3842 /* Decode the name for real. */
3843 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
3845 /* Store the decoded name in the form expected
3846 * by dos.library (which will then translate it again).
3848 fib->fib_FileName[0] = decoded_name_len;
3849 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
3851 else
3853 /* Store the file/directory name in the form expected
3854 * by dos.library.
3856 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
3858 /* If necessary, translate the name to Amiga format using a mapping table. */
3859 if(TranslateNames)
3860 TranslateBName(fib->fib_FileName,M2A);
3863 fib->fib_DirEntryType = st.is_dir ? ST_USERDIR : ST_FILE;
3864 fib->fib_EntryType = fib->fib_DirEntryType;
3865 fib->fib_NumBlocks = (st.size + 511) / 512;
3866 fib->fib_Size = st.size;
3867 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3868 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3870 if(st.is_wp)
3871 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
3873 /* Careful: the 'archive' attribute has exactly the opposite
3874 * meaning in the Amiga and the SMB worlds.
3876 if(NOT st.is_archive)
3877 fib->fib_Protection |= FIBF_ARCHIVE;
3879 if(st.is_system)
3880 fib->fib_Protection |= FIBF_PURE;
3882 if(NOT st.is_dir)
3883 fib->fib_DiskKey = -1;
3887 result = DOSTRUE;
3889 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib->fib_FileName)));
3890 SHOWVALUE(fib->fib_DirEntryType);
3891 SHOWVALUE(fib->fib_NumBlocks);
3892 SHOWVALUE(fib->fib_Size);
3893 SHOWVALUE(fib->fib_Date.ds_Days);
3894 SHOWVALUE(fib->fib_Date.ds_Minute);
3895 SHOWVALUE(fib->fib_Date.ds_Tick);
3896 SHOWVALUE(fib->fib_DiskKey);
3898 out:
3900 (*error_ptr) = error;
3902 RETURN(result);
3903 return(result);
3906 /****************************************************************************/
3908 STATIC BOOL
3909 NameIsAcceptable(STRPTR name,LONG max_len)
3911 BOOL result = FALSE;
3912 UBYTE c;
3914 /* This takes care of "." and "..". */
3915 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
3916 goto out;
3918 /* Now for embedded '/', ':' and '\' characters and
3919 * names that just don't want to fit.
3921 while((c = (*name++)) != '\0')
3923 max_len--;
3924 if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
3925 goto out;
3928 result = TRUE;
3930 out:
3932 return(result);
3935 /****************************************************************************/
3937 static int
3938 dir_scan_callback_func_exnext(
3939 struct FileInfoBlock * fib,
3940 int unused_fpos,
3941 int nextpos,
3942 char * name,
3943 int eof,
3944 smba_stat_t * st)
3946 int result = 0;
3947 LONG name_len;
3948 LONG seconds;
3950 ENTER();
3952 D((" '%s'",name));
3953 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
3954 st->is_dir,st->is_wp,st->is_hidden,st->size));
3955 D((" nextpos=%ld eof=%ld",nextpos,eof));
3957 /* Skip file and drawer names that we wouldn't be
3958 * able to handle in the first place.
3960 if(!NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) || (st->is_hidden && OmitHidden))
3961 goto out;
3963 name_len = strlen(name);
3965 if(TranslateUTF8)
3967 UBYTE decoded_name[MAX_FILENAME_LEN];
3968 int decoded_name_len;
3970 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
3971 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
3972 goto out;
3974 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
3976 fib->fib_FileName[0] = decoded_name_len;
3977 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
3979 else
3981 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
3983 if(TranslateNames)
3984 TranslateBName(fib->fib_FileName,M2A);
3987 fib->fib_DirEntryType = st->is_dir ? ST_USERDIR : ST_FILE;
3988 fib->fib_EntryType = fib->fib_DirEntryType;
3989 fib->fib_NumBlocks = (st->size + 511) / 512;
3990 fib->fib_Size = st->size;
3991 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
3992 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
3994 if(st->is_wp)
3995 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
3997 /* Careful: the 'archive' attribute has exactly the opposite
3998 * meaning in the Amiga and the SMB worlds.
4000 if(NOT st->is_archive)
4001 fib->fib_Protection |= FIBF_ARCHIVE;
4003 if(st->is_system)
4004 fib->fib_Protection |= FIBF_PURE;
4006 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4007 seconds = (st->mtime == 0 ? st->ctime : st->mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4008 if(seconds < 0)
4009 seconds = 0;
4011 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
4012 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
4013 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
4015 result = 1;
4017 out:
4019 fib->fib_DiskKey = eof ? -1 : nextpos;
4021 RETURN(result);
4022 return(result);
4025 STATIC LONG
4026 Action_ExamineNext(
4027 struct FileLock * lock,
4028 struct FileInfoBlock * fib,
4029 SIPTR * error_ptr)
4031 struct LockNode * ln;
4032 LONG result = DOSFALSE;
4033 LONG error = OK;
4034 long offset;
4035 int count;
4037 ENTER();
4039 SHOWVALUE(lock);
4041 if(fib->fib_DiskKey == -1)
4043 SHOWMSG("scanning finished.");
4044 error = ERROR_NO_MORE_ENTRIES;
4045 goto out;
4048 if(lock == NULL)
4050 SHOWMSG("invalid lock");
4051 error = ERROR_INVALID_LOCK;
4052 goto out;
4055 offset = fib->fib_DiskKey;
4057 ln = (struct LockNode *)lock->fl_Key;
4059 /* Check if we should restart scanning the directory
4060 * contents. This is tricky at best and may produce
4061 * irritating results :(
4063 if(ln->ln_RestartExamine)
4065 offset = 0;
4067 ln->ln_RestartExamine = FALSE;
4070 memset(fib,0,sizeof(*fib));
4072 SHOWMSG("calling 'smba_readdir'");
4073 SHOWVALUE(offset);
4075 count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
4077 SHOWVALUE(count);
4079 if(count == 0 || fib->fib_FileName[0] == '\0')
4081 SHOWMSG("nothing to be read");
4082 fib->fib_DiskKey = -1;
4084 error = ERROR_NO_MORE_ENTRIES;
4085 goto out;
4087 else if (count == (-EIO))
4089 SHOWMSG("ouch! directory read error");
4090 fib->fib_DiskKey = -1;
4092 error = ERROR_NO_DEFAULT_DIR;
4093 goto out;
4095 else if (count < 0)
4097 SHOWMSG("error whilst scanning");
4098 SHOWVALUE(count);
4099 fib->fib_DiskKey = -1;
4101 error = MapErrnoToIoErr(count);
4102 goto out;
4105 result = DOSTRUE;
4107 out:
4109 (*error_ptr) = error;
4111 RETURN(result);
4112 return(result);
4115 /****************************************************************************/
4117 struct ExAllContext
4119 struct ExAllData * ec_Last;
4120 struct ExAllData * ec_Next;
4121 ULONG ec_BytesLeft;
4122 ULONG ec_MinSize;
4123 struct ExAllControl * ec_Control;
4124 ULONG ec_Type;
4125 LONG ec_Error;
4126 BOOL ec_FirstAttempt;
4129 static int
4130 dir_scan_callback_func_exall(
4131 struct ExAllContext * ec,
4132 int unused_fpos,
4133 int nextpos,
4134 char * name,
4135 int eof,
4136 smba_stat_t * st)
4138 UBYTE decoded_name[MAX_FILENAME_LEN];
4139 BOOL ignore_this_entry = FALSE;
4140 int result = 0;
4142 ENTER();
4144 D((" '%s'",name));
4145 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4146 st->is_dir,st->is_wp,st->is_hidden,st->size));
4147 D((" nextpos=%ld eof=%ld",nextpos,eof));
4149 /* If necessary, translate the name of the file first, so that we
4150 * can decide early on whether or not it should show up in a
4151 * directory listing. This filters out, for example, files using
4152 * characters which are not usable on the Amiga because they fall
4153 * outside the 8 bit character set used.
4155 if(TranslateUTF8)
4157 LONG name_len = strlen(name);
4158 int decoded_name_len;
4160 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
4161 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
4163 ignore_this_entry = TRUE;
4165 else
4167 decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
4169 /* Use the decoded replacement name. */
4170 name = decoded_name;
4174 /* Skip file and drawer names that we wouldn't be
4175 * able to handle in the first place.
4177 if(!ignore_this_entry && NameIsAcceptable((STRPTR)name,MAX_FILENAME_LEN) && NOT (st->is_hidden && OmitHidden))
4179 struct ExAllData * ed;
4180 ULONG size;
4181 ULONG type = ec->ec_Type;
4182 BOOL take_it;
4184 size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3UL;
4185 SHOWVALUE(size);
4186 if(size > ec->ec_BytesLeft)
4188 D(("size %ld > ec->ec_BytesLeft %ld",size,ec->ec_BytesLeft));
4190 /* If this is the first directory entry,
4191 * stop the entire process before it has
4192 * really begun.
4194 if(ec->ec_FirstAttempt)
4196 SHOWMSG("this was the first read attempt.");
4197 ec->ec_Control->eac_Entries = 0;
4198 ec->ec_Error = ERROR_NO_FREE_STORE;
4200 else
4202 SHOWMSG("try again");
4203 ec->ec_Error = 0;
4206 result = 1;
4207 goto out;
4210 ed = ec->ec_Next;
4212 ed->ed_Next = NULL;
4213 ed->ed_Name = (STRPTR)(((IPTR)ed) + ec->ec_MinSize);
4214 strcpy(ed->ed_Name,name);
4216 if(!TranslateUTF8 && TranslateNames)
4217 TranslateCName(ed->ed_Name,M2A);
4219 if(type >= ED_TYPE)
4220 ed->ed_Type = st->is_dir ? ST_USERDIR : ST_FILE;
4222 if(type >= ED_SIZE)
4223 ed->ed_Size = st->size;
4225 if(type >= ED_PROTECTION)
4227 ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
4228 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
4230 if(st->is_wp)
4231 ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
4233 /* Careful: the 'archive' attribute has exactly the opposite
4234 * meaning in the Amiga and the SMB worlds.
4236 if(NOT st->is_archive)
4237 ed->ed_Prot |= FIBF_ARCHIVE;
4239 if(st->is_system)
4240 ed->ed_Prot |= FIBF_PURE;
4243 if(type >= ED_DATE)
4245 LONG seconds;
4247 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4248 seconds = (st->mtime == 0 ? st->ctime : st->mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4249 if(seconds < 0)
4250 seconds = 0;
4252 ed->ed_Days = (seconds / (24 * 60 * 60));
4253 ed->ed_Mins = (seconds % (24 * 60 * 60)) / 60;
4254 ed->ed_Ticks = (seconds % 60) * TICKS_PER_SECOND;
4257 if(type >= ED_COMMENT)
4258 ed->ed_Comment = "";
4260 if(type >= ED_OWNER)
4261 ed->ed_OwnerUID = ed->ed_OwnerGID = 0;
4263 take_it = TRUE;
4265 if(ec->ec_Control->eac_MatchString != NULL)
4267 SHOWMSG("checking against match string");
4268 if(NOT MatchPatternNoCase(ec->ec_Control->eac_MatchString,ed->ed_Name))
4270 SHOWMSG("does not match");
4271 take_it = FALSE;
4275 if(take_it && ec->ec_Control->eac_MatchFunc != NULL)
4277 SHOWMSG("calling match func");
4279 /* NOTE: the order of the parameters passed to the match hook
4280 * function can be somewhat confusing. For standard
4281 * hook functions, the order of the parameters and the
4282 * registers they go into is hook=A0, object=A2,
4283 * message=A1. However, the documentation for the 'ExAll()'
4284 * function always lists them in ascending order, that is
4285 * hook=A0, message=A1, object=A2, which can lead to
4286 * quite some confusion and strange errors.
4288 if(NOT CallHookPkt(ec->ec_Control->eac_MatchFunc,&type,ed))
4290 SHOWMSG("does not match");
4291 take_it = FALSE;
4295 if(take_it)
4297 SHOWMSG("registering new entry");
4299 if(ec->ec_Last != NULL)
4300 ec->ec_Last->ed_Next = ed;
4302 ec->ec_Last = ed;
4303 ec->ec_Next = (struct ExAllData *)(((IPTR)ed) + size);
4304 ec->ec_BytesLeft -= size;
4305 ec->ec_Control->eac_Entries++;
4307 SHOWVALUE(ec->ec_Last->ed_Next);
4308 SHOWVALUE(ed->ed_Name);
4309 SHOWVALUE(ed->ed_Comment);
4313 ec->ec_Control->eac_LastKey = (ULONG)(eof ? -1 : nextpos);
4315 out:
4317 ec->ec_FirstAttempt = FALSE;
4319 RETURN(result);
4320 return(result);
4323 STATIC LONG
4324 Action_ExamineAll(
4325 struct FileLock * lock,
4326 struct ExAllData * ed,
4327 ULONG size,
4328 ULONG type,
4329 struct ExAllControl * eac,
4330 SIPTR * error_ptr)
4332 struct ExAllContext ec;
4333 struct LockNode * ln;
4334 LONG result = DOSFALSE;
4335 LONG error = OK;
4336 LONG offset;
4337 int count;
4339 ENTER();
4341 SHOWVALUE(lock);
4343 SHOWVALUE(eac->eac_LastKey);
4345 eac->eac_Entries = 0;
4347 if(size < sizeof(ed->ed_Next))
4349 SHOWMSG("buffer is far too short.");
4350 error = ERROR_NO_FREE_STORE;
4351 goto out;
4354 ed->ed_Next = NULL;
4356 if(eac->eac_LastKey == (ULONG)-1)
4358 SHOWMSG("scanning finished.");
4359 error = ERROR_NO_MORE_ENTRIES;
4360 goto out;
4363 if(lock == NULL)
4365 SHOWMSG("invalid lock");
4366 error = ERROR_INVALID_LOCK;
4367 goto out;
4370 if(type < ED_NAME || type > ED_OWNER)
4372 D(("type %ld not supported",type));
4373 error = ERROR_BAD_NUMBER;
4374 goto out;
4377 SHOWVALUE(type);
4379 memset(&ec,0,sizeof(ec));
4381 ec.ec_Next = ed;
4382 ec.ec_BytesLeft = size;
4383 ec.ec_Control = eac;
4384 ec.ec_Type = type;
4385 ec.ec_Error = ERROR_NO_MORE_ENTRIES;
4386 ec.ec_FirstAttempt = TRUE;
4388 switch(type)
4390 case ED_NAME:
4392 ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
4393 break;
4395 case ED_TYPE:
4397 ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
4398 break;
4400 case ED_SIZE:
4402 ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
4403 break;
4405 case ED_PROTECTION:
4407 ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
4408 break;
4410 case ED_DATE:
4412 ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
4413 break;
4415 case ED_COMMENT:
4417 ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
4418 break;
4420 case ED_OWNER:
4422 ec.ec_MinSize = sizeof(struct ExAllData);
4423 break;
4426 SHOWVALUE(ec.ec_MinSize);
4428 offset = eac->eac_LastKey;
4430 ln = (struct LockNode *)lock->fl_Key;
4432 /* Check if we should restart scanning the directory
4433 * contents. This is tricky at best and may produce
4434 * irritating results :(
4436 if(ln->ln_RestartExamine)
4438 offset = 0;
4440 ln->ln_RestartExamine = FALSE;
4443 if(offset == 0)
4445 smba_stat_t st;
4447 SHOWMSG("first invocation");
4449 SHOWMSG("getting file attributes");
4450 error = smba_getattr(ln->ln_File,&st);
4451 if(error < 0)
4453 SHOWMSG("didn't work");
4454 error = MapErrnoToIoErr(error);
4455 eac->eac_LastKey = (ULONG)-1;
4456 goto out;
4459 if(NOT st.is_dir)
4461 SHOWMSG("lock does not refer to a directory");
4462 error = ERROR_OBJECT_WRONG_TYPE;
4463 eac->eac_LastKey = (ULONG)-1;
4464 goto out;
4468 SHOWMSG("calling 'smba_readdir'");
4469 SHOWVALUE(offset);
4471 count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
4473 SHOWVALUE(count);
4475 if(count == 0 || eac->eac_Entries == 0)
4477 SHOWMSG("nothing to be read");
4478 if(ec.ec_Error != OK)
4480 SHOWMSG("flagging an error");
4481 SHOWVALUE(ec.ec_Error);
4482 eac->eac_LastKey = (ULONG)-1;
4483 error = ec.ec_Error;
4486 goto out;
4488 else if (count == (-EIO))
4490 SHOWMSG("ouch! directory read error");
4491 eac->eac_LastKey = (ULONG)-1;
4493 error = ERROR_NO_DEFAULT_DIR;
4494 goto out;
4496 else if (count < 0)
4498 SHOWMSG("error whilst scanning");
4499 eac->eac_LastKey = (ULONG)-1;
4501 error = MapErrnoToIoErr(count);
4502 goto out;
4505 SHOWMSG("ok");
4506 result = DOSTRUE;
4508 out:
4510 #if DEBUG
4512 SHOWVALUE(eac->eac_Entries);
4514 while(ed != NULL)
4516 SHOWSTRING(ed->ed_Name);
4518 ed = ed->ed_Next;
4521 #endif /* DEBUG */
4523 (*error_ptr) = error;
4525 RETURN(result);
4526 return(result);
4529 /****************************************************************************/
4531 STATIC LONG
4532 Action_Find(
4533 LONG action,
4534 struct FileHandle * fh,
4535 struct FileLock * parent,
4536 APTR bcpl_name,
4537 SIPTR * error_ptr)
4539 LONG result = DOSFALSE;
4540 STRPTR parent_path = NULL;
4541 STRPTR full_name = NULL;
4542 LONG full_name_size;
4543 struct FileNode * fn = NULL;
4544 STRPTR parent_name;
4545 UBYTE name[MAX_FILENAME_LEN];
4546 BOOL create_new_file;
4547 LONG error;
4549 ENTER();
4551 switch(action)
4553 case ACTION_FINDINPUT:
4554 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
4555 break;
4557 case ACTION_FINDOUTPUT:
4558 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
4559 break;
4561 case ACTION_FINDUPDATE:
4562 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
4563 break;
4566 SHOWVALUE(parent);
4568 if(parent != NULL)
4570 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
4572 parent_name = ln->ln_FullName;
4574 else
4576 parent_name = NULL;
4579 ConvertBString(sizeof(name),name,bcpl_name);
4581 if (TranslateUTF8)
4583 UBYTE encoded_name[MAX_FILENAME_LEN];
4584 int encoded_name_len;
4585 LONG name_len = strlen(name);
4587 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
4588 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
4590 error = ERROR_INVALID_COMPONENT_NAME;
4591 goto out;
4594 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
4596 strlcpy(name,encoded_name,sizeof(name));
4598 else if (TranslateNames)
4600 TranslateCName(name,A2M);
4603 if(IsReservedName(FilePart(name)))
4605 error = ERROR_OBJECT_NOT_FOUND;
4606 goto out;
4609 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
4610 if(error != OK)
4611 goto out;
4613 /* Trying to open the root directory? */
4614 if(full_name == NULL)
4616 error = ERROR_OBJECT_WRONG_TYPE;
4617 goto out;
4620 fn = AllocateMemory(sizeof(*fn));
4621 if(fn == NULL)
4623 error = ERROR_NO_FREE_STORE;
4624 goto out;
4627 memset(fn,0,sizeof(*fn));
4629 fn->fn_Handle = fh;
4630 fn->fn_FullName = full_name;
4631 fn->fn_Mode = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK;
4633 error = CheckAccessModeCollision(full_name,fn->fn_Mode);
4634 if(error != OK)
4635 goto out;
4637 SHOWSTRING(full_name);
4639 if(action == ACTION_FINDOUTPUT)
4641 /* Definitely create a new file. */
4642 create_new_file = TRUE;
4644 else if (action == ACTION_FINDINPUT)
4646 /* Open an existing file for reading. */
4647 create_new_file = FALSE;
4649 else if (action == ACTION_FINDUPDATE)
4651 smba_file_t * file = NULL;
4652 smba_stat_t st;
4654 if(smba_open(ServerData,full_name,full_name_size,&file) == OK &&
4655 smba_getattr(file,&st) == OK)
4657 /* File apparently opens Ok and information on it
4658 * is available, don't try to replace it.
4660 create_new_file = FALSE;
4662 else
4664 /* We try to ignore the error here and assume
4665 * that the remainder of the file opening
4666 * procedure will produce a useful error
4667 * report. In the mean time, assume that the
4668 * file needs to be created.
4670 create_new_file = TRUE;
4673 if(file != NULL)
4674 smba_close(file);
4676 else
4678 /* What's that? */
4679 error = ERROR_ACTION_NOT_KNOWN;
4680 goto out;
4683 /* Create a new file? */
4684 if(create_new_file)
4686 smba_stat_t st;
4687 smba_file_t * dir;
4688 STRPTR base_name;
4689 LONG i;
4691 if(WriteProtected)
4693 error = ERROR_DISK_WRITE_PROTECTED;
4694 goto out;
4697 parent_path = AllocateMemory(strlen(full_name)+3);
4698 if(parent_path == NULL)
4700 error = ERROR_NO_FREE_STORE;
4701 goto out;
4704 strcpy(parent_path,full_name);
4705 base_name = NULL;
4706 for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
4708 if(parent_path[i] == SMB_PATH_SEPARATOR)
4710 if(i == 0)
4712 memmove(&parent_path[1],&parent_path[0],strlen(parent_path)+1);
4713 i++;
4716 parent_path[i] = '\0';
4718 base_name = &parent_path[i+1];
4719 break;
4723 SHOWMSG("creating a file; finding parent path first");
4724 SHOWSTRING(parent_path);
4726 error = smba_open(ServerData,parent_path,strlen(full_name)+3,&dir);
4727 if(error < 0)
4729 error = MapErrnoToIoErr(error);
4730 goto out;
4733 /* Only one attribute counts: the file should not be write protected. */
4734 memset(&st,0,sizeof(st));
4736 SHOWMSG("now trying to create the file");
4737 SHOWSTRING(base_name);
4739 error = smba_create(dir,base_name,&st);
4740 if(error < 0)
4742 SHOWMSG("didn't work.");
4743 SHOWVALUE(error);
4745 smba_close(dir);
4746 error = MapErrnoToIoErr(error);
4748 SHOWVALUE(error);
4750 goto out;
4753 SHOWMSG("good.");
4755 smba_close(dir);
4758 /* Now for the remainder... */
4759 error = smba_open(ServerData,full_name,full_name_size,&fn->fn_File);
4760 if(error < 0)
4762 error = MapErrnoToIoErr(error);
4763 goto out;
4766 fh->fh_Arg1 = (IPTR)fn;
4768 AddTail((struct List *)&FileList,(struct Node *)fn);
4769 result = DOSTRUE;
4771 out:
4773 if(result == DOSFALSE)
4775 FreeMemory(full_name);
4776 FreeMemory(fn);
4779 FreeMemory(parent_path);
4781 (*error_ptr) = error;
4783 RETURN(result);
4784 return(result);
4787 /****************************************************************************/
4789 STATIC LONG
4790 Action_Read(
4791 struct FileNode * fn,
4792 APTR mem,
4793 LONG length,
4794 SIPTR * error_ptr)
4796 LONG result = 0;
4797 LONG error = OK;
4799 ENTER();
4801 if(length > 0)
4803 result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
4804 if(result < 0)
4806 error = MapErrnoToIoErr(result);
4807 result = -1;
4808 goto out;
4811 fn->fn_Offset += result;
4814 out:
4816 (*error_ptr) = error;
4818 RETURN(result);
4819 return(result);
4822 /****************************************************************************/
4824 STATIC LONG
4825 Action_Write(
4826 struct FileNode * fn,
4827 APTR mem,
4828 LONG length,
4829 SIPTR * error_ptr)
4831 LONG result = DOSFALSE;
4832 LONG error = OK;
4834 ENTER();
4836 if(WriteProtected)
4838 error = ERROR_DISK_WRITE_PROTECTED;
4839 goto out;
4842 if(length > 0)
4844 result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
4845 if(result < 0)
4847 error = MapErrnoToIoErr(result);
4848 result = -1;
4849 goto out;
4852 fn->fn_Offset += result;
4855 out:
4857 (*error_ptr) = error;
4859 RETURN(result);
4860 return(result);
4863 /****************************************************************************/
4865 STATIC LONG
4866 Action_End(
4867 struct FileNode * fn,
4868 SIPTR * error_ptr)
4870 Remove((struct Node *)fn);
4872 smba_close(fn->fn_File);
4873 FreeMemory(fn->fn_FullName);
4874 FreeMemory(fn);
4876 (*error_ptr) = OK;
4877 return(DOSTRUE);
4880 /****************************************************************************/
4882 STATIC LONG
4883 Action_Seek(
4884 struct FileNode * fn,
4885 LONG position,
4886 LONG mode,
4887 SIPTR * error_ptr)
4889 LONG previous_position = fn->fn_Offset;
4890 LONG result = -1;
4891 LONG offset;
4892 LONG error;
4894 ENTER();
4896 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4897 #if 0
4899 switch(mode)
4901 case OFFSET_BEGINNING:
4903 mode = 0;
4904 break;
4906 case OFFSET_CURRENT:
4908 mode = 1;
4909 break;
4911 case OFFSET_END:
4913 mode = 2;
4914 break;
4916 default:
4918 error = ERROR_ACTION_NOT_KNOWN;
4919 goto out;
4922 error = smba_seek (fn->fn_File, position, mode, (off_t *) &offset);
4923 if(error < 0)
4925 error = MapErrnoToIoErr(error);
4926 goto out;
4929 #endif
4931 /* olsen: This is the original implementation. */
4932 #if 0
4934 smba_stat_t st;
4936 error = smba_getattr(fn->fn_File,&st);
4937 if(error < 0)
4939 error = MapErrnoToIoErr(error);
4940 goto out;
4943 offset = fn->fn_Offset;
4945 switch(mode)
4947 case OFFSET_BEGINNING:
4949 offset = position;
4950 break;
4952 case OFFSET_CURRENT:
4954 offset += position;
4955 break;
4957 case OFFSET_END:
4959 offset = st.size + position;
4960 break;
4962 default:
4964 error = ERROR_ACTION_NOT_KNOWN;
4965 goto out;
4968 if(offset < 0 || offset > st.size)
4970 error = ERROR_SEEK_ERROR;
4971 goto out;
4974 #endif
4976 /* olsen: This is a mix of the two above. First we calculate the absolute
4977 * position, then seek to that position. The SMB server is supposed
4978 * to do its housekeeping before the position is changed. I wish this
4979 * worked differently, but it seems we've got the best of both worlds
4980 * here...
4982 #if 1
4984 smba_stat_t st;
4986 switch(mode)
4988 case OFFSET_BEGINNING:
4990 offset = position;
4991 break;
4993 case OFFSET_CURRENT:
4995 offset = fn->fn_Offset + position;
4996 break;
4998 case OFFSET_END:
5000 error = smba_getattr(fn->fn_File,&st);
5001 if(error < 0)
5003 error = MapErrnoToIoErr(error);
5004 goto out;
5007 offset = st.size + position;
5008 break;
5010 default:
5012 error = ERROR_ACTION_NOT_KNOWN;
5013 goto out;
5016 if(offset < 0)
5018 error = ERROR_SEEK_ERROR;
5019 goto out;
5022 error = smba_seek (fn->fn_File, offset, 0, (off_t *) &offset);
5023 if(error < 0)
5025 error = MapErrnoToIoErr(error);
5026 goto out;
5029 #endif
5031 error = OK;
5033 fn->fn_Offset = offset;
5035 result = previous_position;
5037 out:
5039 (*error_ptr) = error;
5041 RETURN(result);
5042 return(result);
5045 /****************************************************************************/
5047 STATIC LONG
5048 Action_SetFileSize(
5049 struct FileNode * fn,
5050 LONG position,
5051 LONG mode,
5052 SIPTR * error_ptr)
5054 smba_stat_t st;
5055 LONG result = -1;
5056 LONG error;
5057 long offset;
5059 ENTER();
5061 if(WriteProtected)
5063 error = ERROR_DISK_WRITE_PROTECTED;
5064 goto out;
5067 error = smba_getattr(fn->fn_File,&st);
5068 if(error < 0)
5070 error = MapErrnoToIoErr(error);
5071 goto out;
5074 offset = fn->fn_Offset;
5076 switch(mode)
5078 case OFFSET_BEGINNING:
5080 offset = position;
5081 break;
5083 case OFFSET_CURRENT:
5085 offset += position;
5086 break;
5088 case OFFSET_END:
5090 offset = st.size + position;
5091 break;
5093 default:
5095 error = ERROR_ACTION_NOT_KNOWN;
5096 goto out;
5099 if(offset < 0)
5101 error = ERROR_SEEK_ERROR;
5102 goto out;
5105 st.atime = -1;
5106 st.ctime = -1;
5107 st.mtime = -1;
5108 st.size = offset;
5110 error = smba_setattr(fn->fn_File,&st);
5111 if(error < 0)
5113 error = MapErrnoToIoErr(error);
5114 goto out;
5117 if(fn->fn_Offset > offset)
5118 fn->fn_Offset = offset;
5120 result = offset;
5122 out:
5124 (*error_ptr) = error;
5126 RETURN(result);
5127 return(result);
5130 /****************************************************************************/
5132 STATIC LONG
5133 Action_SetDate(
5134 struct FileLock * parent,
5135 APTR bcpl_name,
5136 struct DateStamp * ds,
5137 SIPTR * error_ptr)
5139 LONG result = DOSFALSE;
5140 STRPTR full_name = NULL;
5141 LONG full_name_size;
5142 smba_file_t * file = NULL;
5143 STRPTR parent_name;
5144 UBYTE name[MAX_FILENAME_LEN];
5145 smba_stat_t st;
5146 LONG seconds;
5147 LONG error;
5149 ENTER();
5151 if(WriteProtected)
5153 error = ERROR_DISK_WRITE_PROTECTED;
5154 goto out;
5157 SHOWVALUE(parent);
5159 if(parent != NULL)
5161 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5163 parent_name = ln->ln_FullName;
5165 else
5167 parent_name = NULL;
5170 ConvertBString(sizeof(name),name,bcpl_name);
5172 if (TranslateUTF8)
5174 UBYTE encoded_name[MAX_FILENAME_LEN];
5175 int encoded_name_len;
5176 LONG name_len = strlen(name);
5178 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
5179 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
5181 error = ERROR_INVALID_COMPONENT_NAME;
5182 goto out;
5185 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
5187 strlcpy(name,encoded_name,sizeof(name));
5189 else if (TranslateNames)
5191 TranslateCName(name,A2M);
5194 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5195 if(error != OK)
5196 goto out;
5198 /* Trying to change the date of the root directory? */
5199 if(full_name == NULL)
5201 error = ERROR_OBJECT_IN_USE;
5202 goto out;
5205 SHOWSTRING(full_name);
5207 error = smba_open(ServerData,full_name,full_name_size,&file);
5208 if(error < 0)
5210 error = MapErrnoToIoErr(error);
5211 goto out;
5214 error = smba_getattr(file,&st);
5215 if(error < 0)
5217 error = MapErrnoToIoErr(error);
5218 goto out;
5221 seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
5223 st.atime = -1;
5224 st.ctime = -1;
5225 st.mtime = seconds + UNIX_TIME_OFFSET + GetTimeZoneDelta();
5226 st.size = -1;
5228 error = smba_setattr(file,&st);
5229 if(error < 0)
5231 error = MapErrnoToIoErr(error);
5232 goto out;
5235 result = DOSTRUE;
5237 out:
5239 FreeMemory(full_name);
5241 if(file != NULL)
5242 smba_close(file);
5244 (*error_ptr) = error;
5246 RETURN(result);
5247 return(result);
5250 /****************************************************************************/
5252 STATIC LONG
5253 Action_ExamineFH(
5254 struct FileNode * fn,
5255 struct FileInfoBlock * fib,
5256 SIPTR * error_ptr)
5258 LONG result = DOSFALSE;
5259 smba_stat_t st;
5260 LONG error;
5261 LONG seconds;
5262 STRPTR name;
5263 LONG name_len;
5264 LONG i;
5266 ENTER();
5268 error = smba_getattr(fn->fn_File,&st);
5269 if(error < 0)
5271 error = MapErrnoToIoErr(error);
5272 goto out;
5275 name = fn->fn_FullName;
5276 name_len = strlen(name);
5278 for(i = name_len ; i >= 0 ; i--)
5280 if(name[i] == SMB_PATH_SEPARATOR)
5282 name = &name[i+1];
5283 break;
5287 /* Just checking: will the name fit? */
5288 if(name_len >= sizeof(fib->fib_FileName))
5290 error = ERROR_INVALID_COMPONENT_NAME;
5291 goto out;
5294 memset(fib,0,sizeof(*fib));
5296 if(TranslateUTF8)
5298 UBYTE decoded_name[MAX_FILENAME_LEN];
5299 int decoded_name_len;
5301 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0);
5302 if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN)
5304 error = ERROR_INVALID_COMPONENT_NAME;
5305 goto out;
5308 decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,decoded_name,sizeof(decoded_name));
5310 fib->fib_FileName[0] = decoded_name_len;
5311 memcpy(&fib->fib_FileName[1],decoded_name,decoded_name_len);
5313 else
5315 ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len);
5317 if(TranslateNames)
5318 TranslateBName(fib->fib_FileName,M2A);
5321 fib->fib_DirEntryType = ST_FILE;
5322 fib->fib_EntryType = ST_FILE;
5323 fib->fib_NumBlocks = (st.size + 511) / 512;
5324 fib->fib_Size = st.size;
5325 fib->fib_DiskKey = -1;
5327 fib->fib_Protection = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
5328 FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
5330 if(st.is_wp)
5331 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
5333 /* Careful: the 'archive' attribute has exactly the opposite
5334 * meaning in the Amiga and the SMB worlds.
5336 if(NOT st.is_archive)
5337 fib->fib_Protection |= FIBF_ARCHIVE;
5339 if(st.is_system)
5340 fib->fib_Protection |= FIBF_PURE;
5342 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
5343 seconds = (st.mtime == 0 ? st.ctime : st.mtime) - UNIX_TIME_OFFSET - GetTimeZoneDelta();
5344 if(seconds < 0)
5345 seconds = 0;
5347 fib->fib_Date.ds_Days = (seconds / (24 * 60 * 60));
5348 fib->fib_Date.ds_Minute = (seconds % (24 * 60 * 60)) / 60;
5349 fib->fib_Date.ds_Tick = (seconds % 60) * TICKS_PER_SECOND;
5351 result = DOSTRUE;
5353 out:
5355 (*error_ptr) = error;
5357 RETURN(result);
5358 return(result);
5361 /****************************************************************************/
5363 STATIC BPTR
5364 Action_ParentFH(
5365 struct FileNode * fn,
5366 SIPTR * error_ptr)
5368 BPTR result = ZERO;
5369 struct LockNode * ln = NULL;
5370 LONG error;
5371 STRPTR full_name;
5372 LONG full_name_size;
5373 LONG i;
5375 ENTER();
5377 full_name_size = strlen(fn->fn_FullName)+3;
5378 if(full_name_size < SMB_MAXNAMELEN+1)
5379 full_name_size = SMB_MAXNAMELEN+1;
5381 full_name = AllocateMemory(full_name_size);
5382 if(full_name == NULL)
5384 error = ERROR_NO_FREE_STORE;
5385 goto out;
5388 strcpy(full_name,fn->fn_FullName);
5390 for(i = strlen(full_name)-1 ; i >= 0 ; i--)
5392 if(i == 0)
5394 strcpy(full_name,SMB_ROOT_DIR_NAME);
5395 break;
5397 else if (full_name[i] == SMB_PATH_SEPARATOR)
5399 full_name[i] = '\0';
5400 break;
5404 ln = AllocateMemory(sizeof(*ln));
5405 if(ln == NULL)
5407 error = ERROR_NO_FREE_STORE;
5408 goto out;
5411 memset(ln,0,sizeof(*ln));
5413 ln->ln_FileLock.fl_Key = (IPTR)ln;
5414 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5415 ln->ln_FileLock.fl_Task = FileSystemPort;
5416 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5417 ln->ln_FullName = full_name;
5419 SHOWSTRING(full_name);
5421 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5422 if(error < 0)
5424 error = MapErrnoToIoErr(error);
5425 goto out;
5428 AddTail((struct List *)&LockList,(struct Node *)ln);
5429 result = MKBADDR(&ln->ln_FileLock);
5430 SHOWVALUE(&ln->ln_FileLock);
5432 out:
5434 if(result == ZERO)
5436 FreeMemory(ln);
5437 FreeMemory(full_name);
5440 (*error_ptr) = error;
5442 RETURN(result);
5443 return(result);
5446 /****************************************************************************/
5448 STATIC BPTR
5449 Action_CopyDirFH(
5450 struct FileNode * fn,
5451 SIPTR * error_ptr)
5453 BPTR result = ZERO;
5454 struct LockNode * ln = NULL;
5455 STRPTR full_name = NULL;
5456 LONG full_name_size;
5457 LONG error;
5459 ENTER();
5461 if(fn->fn_Mode != SHARED_LOCK)
5463 error = ERROR_OBJECT_IN_USE;
5464 goto out;
5467 full_name_size = strlen(fn->fn_FullName)+3;
5468 if(full_name_size < SMB_MAXNAMELEN+1)
5469 full_name_size = SMB_MAXNAMELEN+1;
5471 full_name = AllocateMemory(full_name_size);
5472 if(full_name == NULL)
5474 error = ERROR_NO_FREE_STORE;
5475 goto out;
5478 strcpy(full_name,fn->fn_FullName);
5480 ln = AllocateMemory(sizeof(*ln));
5481 if(ln == NULL)
5483 error = ERROR_NO_FREE_STORE;
5484 goto out;
5487 memset(ln,0,sizeof(*ln));
5489 ln->ln_FileLock.fl_Key = (IPTR)ln;
5490 ln->ln_FileLock.fl_Access = SHARED_LOCK;
5491 ln->ln_FileLock.fl_Task = FileSystemPort;
5492 ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode);
5493 ln->ln_FullName = full_name;
5495 SHOWSTRING(full_name);
5497 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
5498 if(error < 0)
5500 error = MapErrnoToIoErr(error);
5501 goto out;
5504 AddTail((struct List *)&LockList,(struct Node *)ln);
5505 result = MKBADDR(&ln->ln_FileLock);
5506 SHOWVALUE(&ln->ln_FileLock);
5508 out:
5510 if(result == ZERO)
5512 FreeMemory(ln);
5513 FreeMemory(full_name);
5516 (*error_ptr) = error;
5518 RETURN(result);
5519 return(result);
5522 /****************************************************************************/
5524 STATIC LONG
5525 Action_FHFromLock(
5526 struct FileHandle * fh,
5527 struct FileLock * fl,
5528 SIPTR * error_ptr)
5530 LONG result = DOSFALSE;
5531 struct FileNode * fn;
5532 struct LockNode * ln;
5533 LONG error = OK;
5535 ENTER();
5537 SHOWVALUE(fl);
5539 fn = AllocateMemory(sizeof(*fn));
5540 if(fn == NULL)
5542 error = ERROR_NO_FREE_STORE;
5543 goto out;
5546 memset(fn,0,sizeof(*fn));
5548 ln = (struct LockNode *)fl->fl_Key;
5550 fn->fn_Handle = fh;
5551 fn->fn_FullName = ln->ln_FullName;
5552 fn->fn_File = ln->ln_File;
5553 fn->fn_Mode = fl->fl_Access;
5555 Remove((struct Node *)ln);
5556 FreeMemory(ln);
5558 fh->fh_Arg1 = (IPTR)fn;
5560 AddTail((struct List *)&FileList,(struct Node *)fn);
5561 result = DOSTRUE;
5563 out:
5565 (*error_ptr) = error;
5567 RETURN(result);
5568 return(result);
5571 /****************************************************************************/
5573 STATIC LONG
5574 Action_RenameDisk(
5575 APTR bcpl_name,
5576 SIPTR * error_ptr)
5578 LONG result = DOSFALSE;
5579 LONG error = OK;
5580 STRPTR old_name;
5581 STRPTR new_name;
5582 UBYTE * name;
5583 LONG len;
5585 ENTER();
5587 if(NOT VolumeNodeAdded)
5589 error = ERROR_OBJECT_IN_USE;
5590 goto out;
5593 if(WriteProtected)
5595 error = ERROR_DISK_WRITE_PROTECTED;
5596 goto out;
5599 /* Now for the really interesting part; the new name
5600 * is to be a NUL-terminated BCPL string, and as such
5601 * must be allocated via AllocVec().
5604 name = bcpl_name;
5606 len = name[0];
5608 new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
5609 if(new_name == NULL)
5611 error = ERROR_NO_FREE_STORE;
5612 goto out;
5615 new_name[0] = len;
5616 memcpy(&new_name[1],&name[1],len);
5617 new_name[len+1] = '\0';
5619 Forbid();
5621 old_name = BADDR(VolumeNode->dol_Name);
5622 VolumeNode->dol_Name = MKBADDR(new_name);
5624 Permit();
5626 FreeVec(old_name);
5628 SendDiskChange(IECLASS_DISKINSERTED);
5630 result = DOSTRUE;
5632 out:
5634 (*error_ptr) = error;
5636 RETURN(result);
5637 return(result);
5640 /****************************************************************************/
5642 STATIC LONG
5643 Action_ChangeMode(
5644 LONG type,
5645 APTR object,
5646 LONG new_mode,
5647 SIPTR * error_ptr)
5649 LONG result = DOSFALSE;
5650 struct FileLock * fl = NULL;
5651 struct FileNode * fn = NULL;
5652 struct LockNode * ln = NULL;
5653 STRPTR name;
5654 LONG old_mode;
5655 LONG error = OK;
5657 ENTER();
5659 /* Sanity check; verify parameters */
5660 if((type != CHANGE_LOCK && type != CHANGE_FH) ||
5661 (new_mode != EXCLUSIVE_LOCK && new_mode != SHARED_LOCK))
5663 error = ERROR_ACTION_NOT_KNOWN;
5664 goto out;
5667 /* Now obtain the data structures, name and mode
5668 * associated with the object in question.
5670 if(type == CHANGE_LOCK)
5672 fl = object;
5673 ln = (struct LockNode *)fl->fl_Key;
5674 name = ln->ln_FullName;
5675 old_mode = fl->fl_Access;
5677 else
5679 struct FileHandle * fh = object;
5681 fn = (struct FileNode *)fh->fh_Arg1;
5682 name = fn->fn_FullName;
5683 old_mode = fn->fn_Mode;
5686 /* Do we need to change anything at all? */
5687 if(new_mode == old_mode)
5689 result = DOSTRUE;
5690 goto out;
5693 /* This is the easiest case; change an
5694 * exclusive access mode to a shared
5695 * access mode. Since the original mode
5696 * can be used by one object only,
5697 * we get away by updating the mode
5698 * value.
5700 if(new_mode == SHARED_LOCK)
5702 if(type == CHANGE_LOCK)
5703 fl->fl_Access = new_mode;
5704 else
5705 fn->fn_Mode = new_mode;
5707 result = DOSTRUE;
5708 goto out;
5711 /* Is there another shared access lock
5712 * which refers to the same object?
5714 if(FindLockNode(name,ln) != NULL)
5716 error = ERROR_OBJECT_IN_USE;
5717 goto out;
5720 /* Is there another shared access file
5721 * which refers to the same object?
5723 if(FindFileNode(name,fn) != NULL)
5725 error = ERROR_OBJECT_IN_USE;
5726 goto out;
5729 /* There is just one single reference
5730 * to this object; change the mode
5731 * and quit.
5733 if(type == CHANGE_LOCK)
5734 fl->fl_Access = new_mode;
5735 else
5736 fn->fn_Mode = new_mode;
5738 result = DOSTRUE;
5740 out:
5742 (*error_ptr) = error;
5744 RETURN(result);
5745 return(result);
5748 /****************************************************************************/
5750 STATIC LONG
5751 Action_WriteProtect(
5752 LONG flag,
5753 ULONG key,
5754 SIPTR * error_ptr)
5756 LONG result = DOSFALSE;
5757 LONG error = OK;
5759 ENTER();
5761 if(flag == DOSFALSE)
5763 if(WriteProtected)
5765 if(key != WriteProtectKey)
5767 error = ERROR_INVALID_LOCK;
5768 goto out;
5771 WriteProtected = FALSE;
5773 if(VolumeNodeAdded)
5775 SendDiskChange(IECLASS_DISKREMOVED);
5776 SendDiskChange(IECLASS_DISKINSERTED);
5780 else
5782 if(NOT WriteProtected)
5784 WriteProtected = TRUE;
5785 WriteProtectKey = key;
5787 if(VolumeNodeAdded)
5789 SendDiskChange(IECLASS_DISKREMOVED);
5790 SendDiskChange(IECLASS_DISKINSERTED);
5793 else
5795 error = ERROR_INVALID_LOCK;
5796 goto out;
5800 result = DOSTRUE;
5802 out:
5804 (*error_ptr) = error;
5806 RETURN(result);
5807 return(result);
5810 /****************************************************************************/
5812 STATIC LONG
5813 Action_MoreCache(
5814 LONG buffer_delta,
5815 SIPTR * error_ptr)
5817 LONG result;
5818 int old_size;
5820 ENTER();
5822 old_size = smba_get_dircache_size(ServerData);
5824 result = smba_change_dircache_size(ServerData,old_size + buffer_delta);
5826 if(result == old_size && buffer_delta != 0)
5828 result = DOSFALSE;
5829 (*error_ptr) = ERROR_NO_FREE_STORE;
5832 RETURN(result);
5833 return(result);
5836 /****************************************************************************/
5838 STATIC LONG
5839 Action_SetComment(
5840 struct FileLock * parent,
5841 APTR bcpl_name,
5842 APTR bcpl_comment,
5843 SIPTR * error_ptr)
5845 LONG result = DOSFALSE;
5846 STRPTR full_name = NULL;
5847 LONG full_name_size;
5848 smba_file_t * file = NULL;
5849 STRPTR parent_name;
5850 UBYTE name[MAX_FILENAME_LEN];
5851 UBYTE comment[80];
5852 LONG error;
5854 ENTER();
5856 if(WriteProtected)
5858 error = ERROR_DISK_WRITE_PROTECTED;
5859 goto out;
5862 SHOWVALUE(parent);
5864 if(parent != NULL)
5866 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5868 parent_name = ln->ln_FullName;
5870 else
5872 parent_name = NULL;
5875 ConvertBString(sizeof(name),name,bcpl_name);
5877 if (TranslateUTF8)
5879 UBYTE encoded_name[MAX_FILENAME_LEN];
5880 int encoded_name_len;
5881 LONG name_len = strlen(name);
5883 encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0);
5884 if(encoded_name_len < 0 || encoded_name_len >= sizeof(name))
5886 error = ERROR_INVALID_COMPONENT_NAME;
5887 goto out;
5890 encode_iso8859_1_as_utf8_string(name,name_len,encoded_name,sizeof(encoded_name));
5892 strlcpy(name,encoded_name,sizeof(name));
5894 else if (TranslateNames)
5896 TranslateCName(name,A2M);
5899 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5900 if(error != OK)
5901 goto out;
5903 /* Trying to change the comment of the root directory? */
5904 if(full_name == NULL)
5906 error = ERROR_OBJECT_IN_USE;
5907 goto out;
5910 SHOWSTRING(full_name);
5912 error = smba_open(ServerData,full_name,full_name_size,&file);
5913 if(error < 0)
5915 error = MapErrnoToIoErr(error);
5916 goto out;
5919 ConvertBString(sizeof(comment),comment,bcpl_comment);
5921 SHOWSTRING(comment);
5923 /* All this work and we're only doing something very silly... */
5924 if(strlen(comment) > 0)
5926 error = ERROR_COMMENT_TOO_BIG;
5927 goto out;
5930 result = DOSTRUE;
5932 out:
5934 FreeMemory(full_name);
5936 if(file != NULL)
5937 smba_close(file);
5939 (*error_ptr) = error;
5941 RETURN(result);
5942 return(result);
5945 /****************************************************************************/
5947 STATIC LONG
5948 Action_LockRecord (
5949 struct FileNode * fn,
5950 LONG offset,
5951 LONG length,
5952 LONG mode,
5953 ULONG timeout,
5954 SIPTR * error_ptr)
5956 LONG result = DOSFALSE;
5957 LONG error;
5958 LONG umode;
5960 /* Sanity checks... */
5961 if (mode < REC_EXCLUSIVE || mode > REC_SHARED_IMMED)
5963 error = ERROR_ACTION_NOT_KNOWN;
5964 goto out;
5967 /* Invalid offset, size or integer overflow? */
5968 if (offset < 0 || length <= 0 || offset + length < offset)
5970 error = ERROR_LOCK_COLLISION;
5971 goto out;
5974 if ((mode == REC_SHARED) || (mode == REC_SHARED_IMMED))
5975 umode = 1;
5976 else
5977 umode = 0;
5979 if ((mode == REC_SHARED_IMMED) || (mode == REC_EXCLUSIVE_IMMED))
5980 timeout = 0;
5982 if (timeout > 0)
5984 if (timeout > 214748364)
5985 timeout = ~0; /* wait forever */
5986 else
5987 timeout *= 20; /* milliseconds instead of Ticks */
5990 error = smba_lockrec (fn->fn_File, offset, length, umode, 0, (long)timeout);
5991 if(error < 0)
5993 error = MapErrnoToIoErr(error);
5994 goto out;
5997 result = DOSTRUE;
5999 out:
6001 (*error_ptr) = error;
6003 RETURN(result);
6004 return(result);
6007 /****************************************************************************/
6009 STATIC LONG
6010 Action_FreeRecord (
6011 struct FileNode * fn,
6012 LONG offset,
6013 LONG length,
6014 SIPTR * error_ptr)
6016 LONG result = DOSFALSE;
6017 LONG error;
6019 /* Sanity checks... */
6020 if(offset < 0 || length <= 0 || offset + length < offset)
6022 error = ERROR_RECORD_NOT_LOCKED;
6023 goto out;
6026 error = smba_lockrec (fn->fn_File, offset, length, 2, -1, 0);
6027 if (error < 0)
6029 error = MapErrnoToIoErr(error);
6030 goto out;
6033 result = DOSTRUE;
6035 out:
6037 (*error_ptr) = error;
6039 RETURN(result);
6040 return(result);
6043 /****************************************************************************/
6045 STATIC VOID
6046 HandleFileSystem(VOID)
6048 struct Process * this_process = (struct Process *)FindTask(NULL);
6049 BOOL sign_off = FALSE;
6050 BYTE old_priority;
6051 ULONG signals;
6052 BOOL done;
6054 ENTER();
6056 DisplayErrorList();
6057 Quiet = TRUE;
6059 done = FALSE;
6061 /* Raise the Task priority of the file system to 10
6062 * unless it already is running at priority 10 or higher.
6064 Forbid();
6066 old_priority = this_process->pr_Task.tc_Node.ln_Pri;
6067 if(old_priority < 10)
6068 SetTaskPri((struct Task *)this_process, 10);
6070 Permit();
6074 signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << FileSystemPort->mp_SigBit));
6076 if(signals & (1UL << FileSystemPort->mp_SigBit))
6078 struct DosPacket * dp;
6079 struct Message * mn;
6080 SIPTR res1,res2;
6082 while((mn = GetMsg(FileSystemPort)) != NULL)
6084 dp = (struct DosPacket *)mn->mn_Node.ln_Name;
6086 D(("got packet; sender '%s'",((struct Node *)dp->dp_Port->mp_SigTask)->ln_Name));
6088 res2 = 0;
6090 if (mn->mn_Node.ln_Type == NT_REPLYMSG)
6092 LONG max_transmit = -1;
6093 if(args.MaxTransmit != NULL)
6094 max_transmit = (*args.MaxTransmit);
6096 AddVolume(
6097 args.DeviceName,
6098 args.VolumeName,
6099 args.Service,
6100 args.Workgroup,
6101 args.UserName,
6102 args.Password,
6103 args.ClientName,
6104 args.ServerName,
6105 (args.CacheSize != NULL) ? *args.CacheSize : 0,
6106 max_transmit,
6107 !args.NetBIOSTransport /* Use raw SMB transport instead of NetBIOS transport? */
6109 continue;
6111 if(!VolumeNodeAdded && dp->dp_Action != ACTION_STARTUP)
6113 res1 = DOSFALSE;
6114 res2 = ERROR_NO_DISK;
6115 ReplyPkt(dp,res1,res2);
6116 continue;
6118 switch(dp->dp_Action)
6120 case ACTION_STARTUP:
6121 /* FSSM,DeviceNode -> Bool */
6123 res1 = (IPTR)Action_Startup(
6124 (struct FileSysStartupMsg *)BADDR(dp->dp_Arg2),
6125 (struct DosList *)BADDR(dp->dp_Arg3),&res2);
6126 if(!res1)
6127 Quit = TRUE;
6128 break;
6130 case ACTION_DIE:
6132 SHOWMSG("ACTION_DIE");
6133 if(IsListEmpty(&FileList) && IsListEmpty(&LockList))
6135 SHOWMSG("no locks or files pending; quitting");
6137 res1 = DOSTRUE;
6139 else
6141 SHOWMSG("locks or files still pending; cannot quit yet");
6143 res1 = DOSFALSE;
6144 res2 = ERROR_OBJECT_IN_USE;
6147 Quit = TRUE;
6148 break;
6150 case ACTION_CURRENT_VOLUME:
6151 /* (Ignore) -> VolumeNode */
6153 res1 = (IPTR)MKBADDR(VolumeNode);
6154 break;
6156 case ACTION_LOCATE_OBJECT:
6157 /* Lock,Name,Mode -> Lock */
6159 res1 = (IPTR)Action_LocateObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6160 break;
6162 case ACTION_RENAME_DISK:
6163 /* Name -> Bool */
6165 res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
6166 break;
6168 case ACTION_FREE_LOCK:
6169 /* Lock -> Bool */
6171 res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6172 break;
6174 case ACTION_DELETE_OBJECT:
6175 /* Lock,Name -> Bool */
6177 res1 = Action_DeleteObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6178 break;
6180 case ACTION_RENAME_OBJECT:
6181 /* Source lock,source name,destination lock,destination name -> Bool */
6183 res1 = Action_RenameObject((struct FileLock *)BADDR(dp->dp_Arg1),BADDR(dp->dp_Arg2),
6184 (struct FileLock *)BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6186 break;
6188 case ACTION_MORE_CACHE:
6189 /* Buffer delta -> Total number of buffers */
6191 /* NOTE: documentation for this packet type is inconsistent;
6192 * in the 'good old' 1.x days 'res1' was documented as
6193 * the total number of buffers to be returned. In the
6194 * 2.x documentation it is said that 'res1' should
6195 * return the success code, with 'res2' to hold the
6196 * total number of buffers. However, the 'AddBuffers'
6197 * shell command doesn't work that way, and the
6198 * dos.library implementation of 'AddBuffers()' doesn't
6199 * work that way either. The 1.3 'AddBuffers' command
6200 * appears to treat a zero result as failure and a
6201 * non-zero result as success, which suggests that this
6202 * is how the packet is supposed to work, contrary to
6203 * what the official documentation says.
6205 res1 = Action_MoreCache(dp->dp_Arg1,&res2);
6206 break;
6208 case ACTION_COPY_DIR:
6209 /* Lock -> Lock */
6211 res1 = (IPTR)Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6212 break;
6214 case ACTION_SET_PROTECT:
6215 /* (Ignore),Lock,Name,Mask -> Bool */
6217 res1 = Action_SetProtect((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),dp->dp_Arg4,&res2);
6218 break;
6220 case ACTION_CREATE_DIR:
6221 /* Lock,Name -> Lock */
6223 res1 = (IPTR)Action_CreateDir((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
6224 break;
6226 case ACTION_EXAMINE_OBJECT:
6227 /* FileLock,FileInfoBlock -> Bool */
6229 res1 = Action_ExamineObject((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6230 break;
6232 case ACTION_EXAMINE_NEXT:
6233 /* FileLock,FileInfoBlock -> Bool */
6235 res1 = Action_ExamineNext((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6236 break;
6238 case ACTION_DISK_INFO:
6239 /* InfoData -> Bool */
6241 Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
6242 res1 = DOSTRUE;
6243 res2 = 0;
6244 break;
6246 case ACTION_INFO:
6247 /* FileLock,InfoData -> Bool */
6249 res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
6250 break;
6252 case ACTION_SET_COMMENT:
6253 /* (Ignore),FileLock,Name,Comment -> Bool */
6255 res1 = Action_SetComment((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
6256 break;
6258 case ACTION_PARENT:
6259 /* Lock -> Lock */
6261 res1 = (IPTR)Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
6262 break;
6264 case ACTION_INHIBIT:
6266 SHOWMSG("ACTION_INHIBIT");
6267 res1 = DOSTRUE;
6268 break;
6270 case ACTION_SET_DATE:
6271 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
6273 res1 = Action_SetDate((struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),(struct DateStamp *)dp->dp_Arg4,&res2);
6274 break;
6276 case ACTION_SAME_LOCK:
6277 /* Lock,Lock -> Bool */
6279 res1 = Action_SameLock((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6280 break;
6282 case ACTION_READ:
6283 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6285 res1 = Action_Read((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6286 break;
6288 case ACTION_WRITE:
6289 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6291 res1 = Action_Write((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
6292 break;
6294 case ACTION_FINDUPDATE:
6295 case ACTION_FINDINPUT:
6296 case ACTION_FINDOUTPUT:
6297 /* FileHandle,FileLock,Name -> Bool */
6299 res1 = Action_Find(dp->dp_Action,(struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),&res2);
6300 break;
6302 case ACTION_END:
6303 /* FileHandle->fh_Arg1 -> Bool */
6305 res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
6306 break;
6308 case ACTION_SEEK:
6309 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6311 res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6312 break;
6314 case ACTION_SET_FILE_SIZE:
6315 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
6317 res1 = Action_SetFileSize((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6318 break;
6320 case ACTION_WRITE_PROTECT:
6321 /* Flag,Key -> Bool */
6323 res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
6324 break;
6326 case ACTION_FH_FROM_LOCK:
6327 /* FileHandle(BPTR),FileLock -> Bool */
6329 res1 = Action_FHFromLock((struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
6330 break;
6332 case ACTION_IS_FILESYSTEM:
6334 SHOWMSG("ACTION_IS_FILESYSTEM");
6335 res1 = DOSTRUE;
6336 break;
6338 case ACTION_CHANGE_MODE:
6339 /* Type,Object,Mode -> Bool */
6341 res1 = Action_ChangeMode(dp->dp_Arg1,(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
6342 break;
6344 case ACTION_COPY_DIR_FH:
6345 /* FileHandle->fh_Arg1 -> Bool */
6347 res1 = (IPTR)Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
6348 break;
6350 case ACTION_PARENT_FH:
6351 /* FileHandle->fh_Arg1 -> Bool */
6353 res1 = (IPTR)Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
6354 break;
6356 case ACTION_EXAMINE_ALL:
6357 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6359 res1 = Action_ExamineAll((struct FileLock *)BADDR(dp->dp_Arg1),(struct ExAllData *)dp->dp_Arg2,
6360 dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2);
6362 break;
6364 case ACTION_EXAMINE_FH:
6365 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
6367 res1 = Action_ExamineFH((struct FileNode *)dp->dp_Arg1,(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
6368 break;
6370 case ACTION_EXAMINE_ALL_END:
6371 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6373 res1 = DOSTRUE;
6374 break;
6376 case ACTION_LOCK_RECORD:
6377 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
6378 res1 = Action_LockRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,dp->dp_Arg4,(ULONG)dp->dp_Arg5,&res2);
6379 break;
6381 case ACTION_FREE_RECORD:
6382 /* FileHandle->fh_Arg1,position,length -> Bool */
6383 res1 = Action_FreeRecord((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
6384 break;
6386 default:
6388 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
6390 /* Return -1 for ACTION_READ_LINK, for which DOSFALSE (= 0)
6391 * would otherwise be a valid response. Bug fix contributed
6392 * by Harry 'Piru' Sintonen.
6394 res1 = (dp->dp_Action == ACTION_READ_LINK) ? -1 : DOSFALSE;
6395 res2 = ERROR_ACTION_NOT_KNOWN;
6397 break;
6400 SHOWVALUE(res1);
6401 SHOWVALUE(res2);
6403 ReplyPkt(dp,res1,res2);
6405 D(("\n"));
6409 #if DEBUG
6411 if(signals & SIGBREAKF_CTRL_F)
6413 struct FileNode * fn;
6414 struct LockNode * ln;
6416 D(("list of open files:"));
6418 for(fn = (struct FileNode *)FileList.mlh_Head ;
6419 fn->fn_MinNode.mln_Succ != NULL ;
6420 fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
6422 D((" name='%s'",fn->fn_FullName));
6423 D((" mode=%ld, offset=%ld",fn->fn_Mode,fn->fn_Offset));
6424 D((""));
6427 D(("list of allocated locks:"));
6429 for(ln = (struct LockNode *)LockList.mlh_Head ;
6430 ln->ln_MinNode.mln_Succ != NULL ;
6431 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
6433 D((" name='%s'",ln->ln_FullName));
6434 D((" mode=%ld",ln->ln_FileLock.fl_Access));
6435 D((""));
6439 #endif /* DEBUG */
6441 if(signals & SIGBREAKF_CTRL_C)
6442 Quit = TRUE;
6444 if(Quit)
6446 if(IsListEmpty(&FileList) && IsListEmpty(&LockList))
6448 SHOWMSG("no locks or files pending; quitting");
6449 done = TRUE;
6451 else
6453 SHOWMSG("locks or files still pending; cannot quit yet");
6457 while(NOT done);
6459 /* Restore the priority of the file system, unless the priority
6460 * has already been changed.
6462 Forbid();
6464 if(old_priority < 10 && this_process->pr_Task.tc_Node.ln_Pri == 10)
6465 SetTaskPri((struct Task *)this_process, old_priority);
6467 Permit();
6469 if(sign_off)
6470 LocalPrintf("stopped.\n");
6472 LEAVE();
6475 /****************************************************************************/
6478 * Copy src to string dst of size siz. At most siz-1 characters
6479 * will be copied. Always NUL terminates (unless siz == 0).
6480 * Returns strlen(src); if retval >= siz, truncation occurred.
6482 size_t
6483 strlcpy(char *dst, const char *src, size_t siz)
6485 char *d = dst;
6486 const char *s = src;
6487 size_t n = siz;
6488 size_t result;
6490 /* Copy as many bytes as will fit */
6491 if(n != 0 && --n != 0)
6495 if(((*d++) = (*s++)) == '\0')
6496 break;
6498 while(--n != 0);
6501 /* Not enough room in dst, add NUL and traverse rest of src */
6502 if(n == 0)
6504 if(siz != 0)
6505 (*d) = '\0'; /* NUL-terminate dst */
6507 while((*s++) != '\0')
6511 result = s - src - 1; /* count does not include NUL */
6513 return(result);
6517 * Appends src to string dst of size siz (unlike strncat, siz is the
6518 * full size of dst, not space left). At most siz-1 characters
6519 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
6520 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
6521 * If retval >= siz, truncation occurred.
6523 size_t
6524 strlcat(char *dst, const char *src, size_t siz)
6526 char *d = dst;
6527 const char *s = src;
6528 size_t n = siz;
6529 size_t dlen;
6530 size_t result;
6532 /* Find the end of dst and adjust bytes left but don't go past end */
6533 while(n-- != 0 && (*d) != '\0')
6534 d++;
6536 dlen = d - dst;
6537 n = siz - dlen;
6539 if(n == 0)
6541 result = dlen + strlen(s);
6543 else
6545 while((*s) != '\0')
6547 if(n != 1)
6549 (*d++) = (*s);
6550 n--;
6553 s++;
6556 (*d) = '\0';
6558 result = dlen + (s - src); /* count does not include NUL */
6561 return(result);