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
35 /****************************************************************************/
37 #include "smb_abstraction.h"
38 #include "utf-8-iso-8859-1-conversion.h"
41 /****************************************************************************/
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
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
;
74 CONST TEXT HandlerName
[] = "smb-handler";
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 /****************************************************************************/
91 typedef LONG
* NUMBER
;
94 /****************************************************************************/
98 struct MinNode fn_MinNode
;
99 struct FileHandle
* fn_Handle
;
102 smba_file_t
* fn_File
;
108 struct MinNode ln_MinNode
;
109 struct FileLock ln_FileLock
;
110 smba_file_t
* ln_File
;
111 BOOL ln_RestartExamine
;
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. */
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
);
167 VOID VARARGS68K
ReportError(STRPTR fmt
, ...);
168 VOID VARARGS68K
SPrintf(STRPTR buffer
, STRPTR formatString
, ...);
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
);
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
;
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__)
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
;
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];
326 SWITCH CaseSensitive
;
336 NUMBER TimeZoneOffset
;
338 SWITCH NetBIOSTransport
;
345 STRPTR cmd_template
=
346 "DOMAIN=WORKGROUP/K,"
350 "CASE=CASESENSITIVE/S,"
353 "CLIENT=CLIENTNAME/K,"
354 "SERVER=SERVERNAME/K,"
355 "DEVICE=DEVICENAME/K,"
356 "VOLUME=VOLUMENAME/K,"
357 "CACHE=CACHESIZE/N/K,"
359 "DEBUGLEVEL=DEBUG/N/K,"
360 "TZ=TIMEZONEOFFSET/N/K,"
365 "TRANSLATE=TRANSLATIONFILE/K,"
368 /****************************************************************************/
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__ */
384 FileSystemPort
= &((*(struct Process
*)FindTask(NULL
)).pr_MsgPort
);
386 /* Don't emit any debugging output before we are ready. */
389 /* Open the libraries we need and check
390 * whether we could get them.
392 DOSBase
= OpenLibrary("dos.library",0);
394 #if defined(__amigaos4__)
398 IDOS
= (struct DOSIFace
*)GetInterface(DOSBase
, "main", 1, 0);
401 CloseLibrary(DOSBase
);
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);
417 CloseLibrary(UtilityBase
);
422 #endif /* __amigaos4__ */
424 if(UtilityBase
== NULL
|| DOSBase
== NULL
|| DOSBase
->lib_Version
< MINIMUM_OS_VERSION
)
427 /* This needs to be set up properly for ReportError()
430 NewList((struct List
*)&ErrorList
);
433 SHOWVALUE(Locale
->loc_GMTOffset
);
444 /****************************************************************************/
447 #define LocalPrintf(format,args...) Printf(format ,##args )
450 LocalPrintf(STRPTR format
, ...)
455 #if defined(__amigaos4__)
457 va_startlinear(args
,format
);
458 result
= VPrintf(format
,va_getlinearva(args
,APTR
));
463 va_start(args
,format
);
464 result
= VPrintf(format
,args
);
467 #endif /* __amigaos4__ */
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.
479 amitcp_strerror(int error
)
481 struct TagItem tags
[2];
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
;
498 /****************************************************************************/
500 /* Return the descriptive text associated with a host lookup failure code. */
502 host_strerror(int error
)
504 struct TagItem tags
[2];
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
;
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
530 CompareNames(STRPTR a
,STRPTR b
)
535 result
= strcmp(a
,b
);
537 result
= Stricmp(a
,b
);
542 /****************************************************************************/
544 /* Translate a string into all upper case characters. */
546 StringToUpper(STRPTR s
)
550 while((c
= (*s
)) != '\0')
554 /****************************************************************************/
556 /* Prepare the accumulated list of error messages for display
557 * and purge the contents of that list.
560 DisplayErrorList(VOID
)
562 struct MinNode
* last
= NULL
;
568 /* Determine how much memory will have to be
569 * allocated to hold all the accumulated
574 for(mn
= ErrorList
.mlh_Head
;
575 mn
->mln_Succ
!= NULL
;
580 msg
= (STRPTR
)(mn
+ 1);
582 len
+= strlen(msg
)+1;
585 /* Allocate the memory for the messages, then
590 str
= AllocVec(len
,MEMF_ANY
);
595 for(mn
= ErrorList
.mlh_Head
;
596 mn
->mln_Succ
!= NULL
;
599 msg
= (STRPTR
)(mn
+ 1);
608 /* Purge the list. */
609 while((mn
= (struct MinNode
*)RemHead((struct List
*)&ErrorList
)) != NULL
)
612 /* Display the error messages. */
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
);
639 es
.es_TextFormat
= str
;
640 es
.es_GadgetFormat
= "Ok";
642 EasyRequestArgs(NULL
,&es
,NULL
,NULL
);
648 #if defined(__amigaos4__)
650 if(IIntuition
!= NULL
)
652 DropInterface((struct Interface
*)IIntuition
);
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
668 AddError(STRPTR fmt
,APTR args
)
672 len
= CVSPrintf(fmt
,args
);
677 mn
= AllocVec(sizeof(*mn
) + len
,MEMF_ANY
|MEMF_PUBLIC
);
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.
694 ReportError(STRPTR fmt
,...)
700 if(WBStartup
!= NULL
)
702 #if defined(__amigaos4__)
704 va_startlinear(args
,fmt
);
705 AddError(fmt
,va_getlinearva(args
,APTR
));
714 #endif /* __amigaos4__ */
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
));
736 #endif /* __amigaos4__ */
744 /****************************************************************************/
746 /* Release memory allocated from the global pool. */
748 FreeMemory(APTR address
)
752 ULONG
* mem
= address
;
756 if(GETDEBUGLEVEL() > 0)
757 memset(address
,0xA3,mem
[-1] - sizeof(*mem
));
761 FreePooled(MemoryPool
,&mem
[-1],mem
[-1]);
765 /* Allocate memory from the global pool. */
767 AllocateMemory(ULONG size
)
775 size
= (sizeof(*mem
) + size
+ 7) & ~7UL;
777 mem
= AllocPooled(MemoryPool
,size
);
784 if(GETDEBUGLEVEL() > 0)
785 memset(mem
,0xA5,mem
[-1] - sizeof(*mem
));
796 /****************************************************************************/
798 /* Obtain the number of seconds to add to the current time
799 * to translate local time into UTC.
802 GetTimeZoneDelta(VOID
)
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
;
824 return(seconds
+ DSTOffset
);
827 /****************************************************************************/
829 /* Obtain the current time, in standard Unix format, adjusted for the
838 GetSysTime((APTR
)&tv
);
840 result
= UNIX_TIME_OFFSET
+ GetTimeZoneDelta() + tv
.tv_secs
;
845 /****************************************************************************/
847 /* Fill in a 'tm' type time specification with time information
848 * corresponding to the number of seconds provided. Input is
852 GMTime(time_t seconds
,struct tm
* tm
)
854 struct ClockData clock_data
;
856 if(seconds
< UNIX_TIME_OFFSET
)
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.
877 MakeTime(const struct tm
* const tm
)
879 struct ClockData clock_data
;
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
;
894 /****************************************************************************/
896 #if !defined(__AROS__)
903 /****************************************************************************/
906 CountChar(REG(a3
,struct FormatContext
* fc
))
911 /* Count the number of characters SPrintf() would put into a string. */
913 CVSPrintf(STRPTR format_string
,APTR args
)
915 struct FormatContext fc
;
919 RawDoFmt((STRPTR
)format_string
,args
,(VOID (*)())CountChar
,&fc
);
924 /****************************************************************************/
927 StuffChar(REG(d0
,UBYTE c
),REG(a3
,struct FormatContext
* fc
))
929 (*fc
->fc_Buffer
++) = c
;
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. */
946 SPrintf(STRPTR buffer
, STRPTR formatString
,...)
950 #if defined(__amigaos4__)
952 va_startlinear(varArgs
,formatString
);
953 VSPrintf(buffer
,formatString
,va_getlinearva(varArgs
,APTR
));
958 va_start(varArgs
,formatString
);
959 VSPrintf(buffer
,formatString
,varArgs
);
962 #endif /* __amigaos4__ */
966 /****************************************************************************/
968 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
969 * Thanks very much, Chris!
973 unsigned short flags
;
974 unsigned char address
[4];
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
;
988 L1_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
)
994 while(('\0' != name
[i
]) && (i
< 15))
996 k
= ToUpper(name
[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);
1011 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
1012 dst
[31] = 'A' + (sfx
& 0x0F);
1019 L2_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
, const UBYTE
* scope
)
1025 if(NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
1031 if('\0' != (*scope
))
1035 for(i
= 0, j
= (lenpos
+ 1);
1036 ('.' != scope
[i
]) && ('\0' != scope
[i
]);
1039 dst
[j
] = ToUpper(scope
[i
]);
1042 dst
[lenpos
] = (UBYTE
)i
;
1046 while('.' == (*scope
++));
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] =
1076 int option_true
= 1;
1077 struct sockaddr_in sox
;
1078 struct nmb_header nmb_header
;
1087 sock_fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1090 SHOWMSG("couldn't get the socket");
1095 if(setsockopt(sock_fd
, SOL_SOCKET
, SO_BROADCAST
, &option_true
, sizeof(option_true
)) < 0)
1097 SHOWMSG("couldn't enable the broadcast option");
1102 sox
.sin_family
= AF_INET
;
1103 sox
.sin_addr
.s_addr
= htonl(0xFFFFFFFF);
1105 s
= getservbyname("netbios-ns","udp");
1107 sox
.sin_port
= s
->s_port
;
1109 sox
.sin_port
= htons(137);
1111 memcpy(buffer
, header
, (total_len
= sizeof(header
)));
1113 n
= L2_Encode(&buffer
[total_len
], name
, ' ', '\0', scope
);
1116 SHOWMSG("name encoding failed");
1122 memcpy(&buffer
[total_len
], query_tail
, sizeof(query_tail
));
1123 total_len
+= sizeof(query_tail
);
1128 /* Send the query packet; retry five times with a one second
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");
1140 /* Wait for a response to arrive. */
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
);
1152 SHOWMSG("could not pick up the response packet");
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
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
)
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);
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);
1216 CloseSocket(sock_fd
);
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.
1229 SendDiskChange(ULONG
class)
1231 struct IOStdReq
* input_request
= NULL
;
1232 struct MsgPort
* input_port
;
1233 struct InputEvent ie
;
1237 input_port
= CreateMsgPort();
1238 if(input_port
== NULL
)
1241 input_request
= (struct IOStdReq
*)CreateIORequest(input_port
,sizeof(*input_request
));
1242 if(input_request
== NULL
)
1245 if(OpenDevice("input.device",0,(struct IORequest
*)input_request
,0) != OK
)
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
);
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
);
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
)
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
)
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
1332 CheckAccessModeCollision(STRPTR name
,LONG mode
)
1334 struct LockNode
* ln
;
1335 struct FileNode
* fn
;
1341 fn
= FindFileNode(name
,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
;
1352 ln
= FindLockNode(name
,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
;
1369 /* Find out whether there already exists a reference to a
1370 * certain file or directory.
1373 NameAlreadyInUse(STRPTR name
)
1379 if(FindFileNode(name
,NULL
) != NULL
)
1381 error
= ERROR_OBJECT_IN_USE
;
1385 if(FindLockNode(name
,NULL
) != NULL
)
1387 error
= ERROR_OBJECT_IN_USE
;
1397 /* Check whether an Amiga file name uses special characters which
1398 * should be avoided when used with the SMB file sharing protocol.
1401 IsReservedName(STRPTR name
)
1403 BOOL result
= FALSE
;
1405 /* Disallow "." and "..". */
1406 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
1414 /* Disallow the use of the backslash in file names. */
1415 while((c
= (*name
++)) != '\0')
1417 if(c
== SMB_PATH_SEPARATOR
)
1428 /****************************************************************************/
1430 /* Convert a POSIX error code into an AmigaDOS error code. */
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 */
1495 LONG result
= ERROR_ACTION_NOT_KNOWN
;
1503 for(i
= 0 ; Map
[i
][0] != -1 ; i
++)
1505 if(Map
[i
][0] == error
)
1516 /****************************************************************************/
1518 /* Translate a BCPL style file name (i.e. length is in the first byte)
1519 * via a mapping table.
1522 TranslateBName(UBYTE
* name
,UBYTE
* map
)
1527 #if !defined(N__AROS__)
1530 len
= AROS_BSTR_strlen(name
);
1531 name
= AROS_BSTR_ADDR(name
);
1541 /* Translate a NUL terminated file name via a mapping table. */
1543 TranslateCName(UBYTE
* name
,UBYTE
* map
)
1547 while((c
= (*name
)) != '\0')
1551 /****************************************************************************/
1553 /* Remove a DosList entry using the proper protocols. Note that
1554 * this function can fail!
1557 ReallyRemoveDosEntry(struct DosList
* entry
)
1559 struct Message
* mn
;
1560 struct MsgPort
* port
;
1561 struct DosList
* dl
;
1562 BOOL result
= FALSE
;
1565 if(entry
->dol_Type
== DLT_DEVICE
)
1570 port
= entry
->dol_Task
;
1572 for(i
= 0 ; i
< 100 ; i
++)
1574 dl
= AttemptLockDosList(LDF_WRITE
|kind
);
1582 UnLockDosList(LDF_WRITE
|kind
);
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);
1598 /****************************************************************************/
1600 /* Release all resources allocated by the Setup() routine. */
1604 BOOL send_disk_change
= FALSE
;
1608 /* If any errors have cropped up, display them now before
1613 if(Parameters
!= NULL
)
1615 FreeArgs(Parameters
);
1621 FreeDiskObject(Icon
);
1625 if(ServerData
!= NULL
)
1627 smba_disconnect(ServerData
);
1631 if(DeviceNode
!= NULL
)
1635 if(ReallyRemoveDosEntry(DeviceNode
))
1636 FreeDosEntry(DeviceNode
);
1640 FreeDosEntry(DeviceNode
);
1646 if(VolumeNode
!= NULL
)
1650 if(ReallyRemoveDosEntry(VolumeNode
))
1651 FreeDosEntry(VolumeNode
);
1653 send_disk_change
= TRUE
;
1657 FreeDosEntry(VolumeNode
);
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__)
1682 DropInterface((struct Interface
*)ITimer
);
1686 #endif /* __amigaos4__ */
1688 if(TimerBase
!= NULL
)
1690 CloseDevice((struct IORequest
*)&TimerRequest
);
1694 #if defined(__amigaos4__)
1698 DropInterface((struct Interface
*)ISocket
);
1702 #endif /* __amigaos4__ */
1704 if(SocketBase
!= NULL
)
1706 CloseLibrary(SocketBase
);
1710 #if defined(__amigaos4__)
1714 DropInterface((struct Interface
*)IIcon
);
1718 #endif /* __amigaos4__ */
1720 if(IconBase
!= NULL
)
1722 CloseLibrary(IconBase
);
1728 CloseLocale(Locale
);
1732 #if defined(__amigaos4__)
1736 DropInterface((struct Interface
*)ILocale
);
1740 #endif /* __amigaos4__ */
1742 if(LocaleBase
!= NULL
)
1744 CloseLibrary(LocaleBase
);
1748 if(MemoryPool
!= NULL
)
1750 DeletePool(MemoryPool
);
1757 /****************************************************************************/
1759 /* Allocate all the necessary resources to get going. */
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
;
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.");
1784 LocaleBase
= OpenLibrary("locale.library",38);
1786 #if defined(__amigaos4__)
1788 if(LocaleBase
!= NULL
)
1790 ILocale
= (struct LocaleIFace
*)GetInterface(LocaleBase
, "main", 1, 0);
1793 CloseLibrary(LocaleBase
);
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'.");
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);
1829 ReportError("Could not open 'timer.device'.");
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);
1845 CloseLibrary(SocketBase
);
1850 #endif /* __amigaos4__ */
1852 if(SocketBase
== NULL
)
1854 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
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
,
1866 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error
,amitcp_strerror(error
));
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
)
1886 file
= Open(translation_file
,MODE_OLDFILE
);
1889 if(Read(file
,A2M
,256) != 256 ||
1890 Read(file
,M2A
,256) != 256)
1892 msg
= "Could not read translation file";
1900 msg
= "Could not open translation file";
1906 TranslateNames
= TRUE
;
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
);
1932 /****************************************************************************/
1935 /* Make connection to server and make a volume for it. */
1943 STRPTR opt_password
,
1944 STRPTR opt_clientname
,
1945 STRPTR opt_servername
,
1947 int opt_max_transmit
,
1950 BOOL result
= FALSE
;
1951 struct DosList
* dl
;
1953 STRPTR actual_volume_name
;
1954 LONG actual_volume_name_len
;
1955 UBYTE name
[MAX_FILENAME_LEN
];
1956 BOOL device_exists
= FALSE
;
1961 error
= smba_start(service
,workgroup
,username
,opt_password
,opt_clientname
,opt_servername
,opt_cachesize
,opt_max_transmit
,opt_raw_smb
,&ServerData
);
1965 /* If a device name was provided, check whether it is
1968 if(device_name
!= NULL
)
1970 len
= strlen(device_name
);
1974 for(i
= 0 ; i
< len
; i
++)
1976 if(device_name
[i
] == '/')
1978 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
1983 /* Lose any trailing colon characters. */
1984 for(i
= len
-1 ; i
>= 0 ; i
--)
1986 if(device_name
[i
] == ':')
1992 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
1996 memcpy(name
,device_name
,len
);
1999 dl
= LockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2001 if(FindDosEntry(dl
,name
,LDF_DEVICES
) != NULL
)
2002 device_exists
= TRUE
;
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
)
2024 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2026 ReportError("Device name '%s:' is already taken.",device_name
);
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.");
2040 DeviceNode
->dol_Task
= FileSystemPort
;
2042 /* Examine the volume name; make sure that it is
2045 if(volume_name
== NULL
)
2046 actual_volume_name
= device_name
;
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
);
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
);
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.");
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. */
2120 SendDiskChange(IECLASS_DISKINSERTED
);
2130 /****************************************************************************/
2132 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2134 ConvertBString(LONG max_len
,STRPTR cstring
,APTR bstring
)
2136 #ifdef AROS_FAST_BSTR
2137 strncpy(cstring
, bstring
, max_len
);
2139 STRPTR from
= bstring
;
2146 memcpy(cstring
,from
+1,len
);
2148 cstring
[len
] = '\0';
2152 /* Convert a NUL terminated 'C' string into a BCPL string. */
2154 ConvertCString(APTR bstring
,LONG max_len
,STRPTR cstring
,LONG len
)
2156 STRPTR to
= bstring
;
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.
2176 STRPTR
* result_ptr
,
2177 LONG
* result_size_ptr
)
2186 SHOWSTRING(parent_name
);
2189 (*result_ptr
) = NULL
;
2191 /* Throw everything left of the colon away. */
2194 for(i
= 0 ; i
< (LONG
)strlen(name
) ; i
++)
2204 /* Now, how much room is needed for the complete
2205 * path to fit into a buffer?
2209 if(parent_name
!= NULL
)
2210 len
+= strlen(parent_name
) + 1;
2213 len
+= strlen(name
) + 1;
2215 if(len
< SMB_MAXNAMELEN
)
2216 len
= SMB_MAXNAMELEN
;
2220 buffer
= AllocateMemory(size
);
2223 error
= ERROR_NO_FREE_STORE
;
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
)
2234 buffer
[0] = SMB_PATH_SEPARATOR
;
2235 strcpy(&buffer
[1],parent_name
);
2239 strcpy(buffer
,SMB_ROOT_DIR_NAME
);
2242 /* If there's a name to add, do just that. */
2250 buffer_len
= strlen(buffer
);
2251 name_len
= strlen(name
);
2259 /* Extract the next path name segment. */
2260 for(i
= segment_start
; i
<= name_len
; i
++)
2264 segment_len
= i
- segment_start
;
2267 else if (name
[i
] == '/')
2269 segment_len
= i
- segment_start
+ 1;
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';
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? */
2298 /* Skip the last path component. */
2299 for(i
= 1 ; i
<= buffer_len
; i
++)
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.
2312 else if (buffer
[buffer_len
-i
] == SMB_PATH_SEPARATOR
)
2314 /* This removes both the path separator and
2315 * the name following it.
2325 /* Add a proper separator character if
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;
2339 memcpy(&buffer
[buffer_len
],&name
[segment_start
],len
);
2343 segment_start
+= segment_len
;
2347 (*result_ptr
) = buffer
;
2348 (*result_size_ptr
) = size
;
2361 /****************************************************************************/
2365 struct FileSysStartupMsg
* fssm
,
2366 struct DosList
* device_node
,
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];
2376 char env_service_name
[17];
2378 BOOL result
= DOSTRUE
;
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
)
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
)
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
;
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
;
2438 ReportError("Required 'SERVICE' parameter was not provided.");
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. */
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
);
2475 /* Enable SMB packet decoding, but only if not started from Workbench. */
2476 #if defined(DUMP_SMB)
2479 control_smb_dump(TRUE
);
2481 #endif /* DUMP_SMB */
2483 D(("%s (%s)",VERS
,DATE
));
2488 args
.TimeZoneOffset
,
2490 args
.TranslationFile
))
2503 !args
.NetBIOSTransport
/* Use raw SMB transport instead of NetBIOS transport? */
2513 (*error_ptr
) = error
;
2519 /****************************************************************************/
2523 struct FileLock
* parent
,
2527 STRPTR full_name
= NULL
;
2528 LONG full_name_size
;
2530 BOOL cleanup
= TRUE
;
2531 struct LockNode
* ln
= NULL
;
2540 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2542 parent_name
= parent_ln
->ln_FullName
;
2549 error
= BuildFullName(parent_name
,"/",&full_name
,&full_name_size
);
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
)
2560 ln
= AllocateMemory(sizeof(*ln
));
2563 error
= ERROR_NO_FREE_STORE
;
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
);
2580 error
= MapErrnoToIoErr(error
);
2584 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2585 result
= MKBADDR(&ln
->ln_FileLock
);
2587 SHOWVALUE(&ln
->ln_FileLock
);
2593 FreeMemory(full_name
);
2597 (*error_ptr
) = error
;
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
;
2616 start
= (struct LockNode
*)last_ln
->ln_MinNode
.mln_Succ
;
2618 start
= (struct LockNode
*)LockList
.mlh_Head
;
2621 ln
->ln_MinNode
.mln_Succ
!= NULL
;
2622 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
2624 if(CompareNames(name
,ln
->ln_FullName
) == SAME
)
2634 /****************************************************************************/
2637 Action_DeleteObject(
2638 struct FileLock
* parent
,
2642 LONG result
= DOSFALSE
;
2643 STRPTR full_name
= NULL
;
2644 LONG full_name_size
;
2645 smba_file_t
* file
= NULL
;
2647 STRPTR full_parent_name
= NULL
;
2648 UBYTE name
[MAX_FILENAME_LEN
];
2649 struct LockNode
* ln
;
2657 error
= ERROR_DISK_WRITE_PROTECTED
;
2665 ln
= (struct LockNode
*)parent
->fl_Key
;
2667 parent_name
= ln
->ln_FullName
;
2674 /* Name string, as given in the DOS packet, is in
2675 * BCPL format and needs to be converted into
2678 ConvertBString(sizeof(name
),name
,bcpl_name
);
2680 /* Translate the Amiga file name into UTF-8 encoded form? */
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
;
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
);
2715 /* Trying to delete the root directory, are you kidding? */
2716 if(full_name
== NULL
)
2718 error
= ERROR_OBJECT_WRONG_TYPE
;
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
;
2733 strcpy(full_parent_name
,full_name
);
2735 /* Build the parent object name - Piru */
2736 if (full_parent_name
[0] != '\0')
2740 i
= strlen(full_parent_name
) - 1;
2741 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2744 for ( ; i
>= 0 ; i
--)
2746 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2748 full_parent_name
[i
] = '\0';
2754 /* NOTE: Mark all locks to this object as restart, not just first
2757 while ((ln
= FindNextLockNode(full_parent_name
, ln
)) != NULL
)
2758 ln
->ln_RestartExamine
= TRUE
;
2760 ln
= FindLockNode(full_parent_name
,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
);
2772 error
= MapErrnoToIoErr(error
);
2776 error
= smba_getattr(file
,&st
);
2779 error
= MapErrnoToIoErr(error
);
2788 SHOWMSG("removing a directory");
2790 error
= smba_rmdir(ServerData
,full_name
);
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
;
2803 error
= MapErrnoToIoErr(error
);
2810 SHOWMSG("removing a file");
2812 error
= smba_remove(ServerData
,full_name
);
2817 error
= MapErrnoToIoErr(error
);
2828 FreeMemory(full_name
);
2829 FreeMemory(full_parent_name
);
2834 (*error_ptr
) = error
;
2840 /****************************************************************************/
2844 struct FileLock
* parent
,
2849 STRPTR full_name
= NULL
;
2850 LONG full_name_size
;
2851 struct LockNode
* ln
= NULL
;
2853 STRPTR dir_name
= NULL
;
2854 smba_file_t
* dir
= NULL
;
2856 UBYTE name
[MAX_FILENAME_LEN
];
2864 error
= ERROR_DISK_WRITE_PROTECTED
;
2872 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2874 parent_name
= parent_ln
->ln_FullName
;
2881 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
);
2909 /* Trying to overwrite the root directory, are you kidding? */
2910 if(full_name
== NULL
)
2912 error
= ERROR_OBJECT_IN_USE
;
2916 dir_name
= AllocateMemory(strlen(full_name
)+3);
2917 if(dir_name
== NULL
)
2919 error
= ERROR_NO_FREE_STORE
;
2923 strcpy(dir_name
,full_name
);
2925 for(i
= strlen(dir_name
)-1 ; i
>= 0 ; i
--)
2927 if(dir_name
[i
] == SMB_PATH_SEPARATOR
)
2931 memmove(&dir_name
[1],&dir_name
[0],strlen(dir_name
)+1);
2937 base_name
= &dir_name
[i
+1];
2942 ln
= AllocateMemory(sizeof(*ln
));
2945 error
= ERROR_NO_FREE_STORE
;
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
);
2960 error
= MapErrnoToIoErr(error
);
2964 error
= smba_mkdir(dir
,base_name
);
2967 error
= MapErrnoToIoErr(error
);
2974 SHOWSTRING(full_name
);
2976 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2979 error
= MapErrnoToIoErr(error
);
2983 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2984 result
= MKBADDR(&ln
->ln_FileLock
);
2985 SHOWVALUE(&ln
->ln_FileLock
);
2992 FreeMemory(dir_name
);
2996 FreeMemory(full_name
);
3000 (*error_ptr
) = error
;
3006 /****************************************************************************/
3009 Action_LocateObject(
3010 struct FileLock
* parent
,
3016 STRPTR full_name
= NULL
;
3017 LONG full_name_size
;
3018 struct LockNode
* ln
= NULL
;
3020 UBYTE name
[MAX_FILENAME_LEN
];
3029 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
3031 parent_name
= parent_ln
->ln_FullName
;
3038 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
;
3068 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3072 /* Trying to get a lock on the root directory's parent?
3075 if(full_name
== NULL
)
3078 ln
= AllocateMemory(sizeof(*ln
));
3081 error
= ERROR_NO_FREE_STORE
;
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
);
3097 SHOWSTRING(full_name
);
3099 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3102 error
= MapErrnoToIoErr(error
);
3106 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3107 result
= MKBADDR(&ln
->ln_FileLock
);
3108 SHOWVALUE(&ln
->ln_FileLock
);
3114 FreeMemory(full_name
);
3118 (*error_ptr
) = error
;
3124 /****************************************************************************/
3128 struct FileLock
* lock
,
3132 STRPTR full_name
= NULL
;
3133 LONG full_name_size
;
3134 struct LockNode
* ln
= NULL
;
3143 if(lock
!= NULL
&& lock
->fl_Access
!= SHARED_LOCK
)
3145 SHOWMSG("cannot duplicate exclusive lock");
3146 error
= ERROR_OBJECT_IN_USE
;
3150 ln
= AllocateMemory(sizeof(*ln
));
3153 error
= ERROR_NO_FREE_STORE
;
3157 memset(ln
,0,sizeof(*ln
));
3161 struct LockNode
* source
= (struct LockNode
*)lock
->fl_Key
;
3163 source_name
= source
->ln_FullName
;
3164 source_mode
= source
->ln_FileLock
.fl_Access
;
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
;
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
);
3196 error
= MapErrnoToIoErr(error
);
3200 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3201 result
= MKBADDR(&ln
->ln_FileLock
);
3202 SHOWVALUE(&ln
->ln_FileLock
);
3208 FreeMemory(full_name
);
3212 (*error_ptr
) = error
;
3218 /****************************************************************************/
3222 struct FileLock
* lock
,
3225 LONG result
= DOSTRUE
;
3226 struct LockNode
* ln
;
3236 ln
= (struct LockNode
*)lock
->fl_Key
;
3238 Remove((struct Node
*)ln
);
3240 smba_close(ln
->ln_File
);
3241 FreeMemory(ln
->ln_FullName
);
3246 (*error_ptr
) = error
;
3252 /****************************************************************************/
3256 struct FileLock
* lock1
,
3257 struct FileLock
* lock2
,
3260 LONG result
= DOSFALSE
;
3272 struct LockNode
* ln
= (struct LockNode
*)lock1
->fl_Key
;
3274 name1
= ln
->ln_FullName
;
3278 name1
= SMB_ROOT_DIR_NAME
;
3283 struct LockNode
* ln
= (struct LockNode
*)lock2
->fl_Key
;
3285 name2
= ln
->ln_FullName
;
3289 name2
= SMB_ROOT_DIR_NAME
;
3295 if(Stricmp(name1
,name2
) == SAME
)
3298 (*error_ptr
) = error
;
3304 /****************************************************************************/
3308 struct FileLock
* parent
,
3313 LONG result
= DOSFALSE
;
3314 STRPTR full_name
= NULL
;
3315 LONG full_name_size
;
3316 smba_file_t
* file
= NULL
;
3318 UBYTE name
[MAX_FILENAME_LEN
];
3326 error
= ERROR_DISK_WRITE_PROTECTED
;
3334 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
3336 parent_name
= ln
->ln_FullName
;
3343 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
);
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
;
3380 SHOWSTRING(full_name
);
3382 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
3385 error
= MapErrnoToIoErr(error
);
3389 memset(&st
,0,sizeof(st
));
3391 mask
^= FIBF_READ
| FIBF_WRITE
| FIBF_EXECUTE
| FIBF_DELETE
;
3398 if((mask
& (FIBF_WRITE
|FIBF_DELETE
)) != (FIBF_WRITE
|FIBF_DELETE
))
3400 SHOWMSG("write protection enabled");
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
);
3419 error
= MapErrnoToIoErr(error
);
3427 FreeMemory(full_name
);
3432 (*error_ptr
) = error
;
3438 /****************************************************************************/
3441 Action_RenameObject(
3442 struct FileLock
* source_lock
,
3443 APTR source_bcpl_name
,
3444 struct FileLock
* destination_lock
,
3445 APTR destination_bcpl_name
,
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
];
3462 error
= ERROR_DISK_WRITE_PROTECTED
;
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
;
3480 ConvertBString(sizeof(name
),name
,source_bcpl_name
);
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
;
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
);
3508 /* Trying to rename the root directory, are you kidding? */
3509 if(full_source_name
== NULL
)
3511 error
= ERROR_OBJECT_IN_USE
;
3515 if(destination_lock
!= NULL
)
3517 ln
= (struct LockNode
*)destination_lock
->fl_Key
;
3519 parent_name
= ln
->ln_FullName
;
3526 ConvertBString(sizeof(name
),name
,destination_bcpl_name
);
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
;
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
);
3554 /* Trying to rename the root directory, are you kidding? */
3555 if(full_destination_name
== NULL
)
3557 error
= ERROR_OBJECT_IN_USE
;
3561 error
= NameAlreadyInUse(full_source_name
);
3565 error
= NameAlreadyInUse(full_destination_name
);
3569 SHOWSTRING(full_source_name
);
3570 SHOWSTRING(full_destination_name
);
3572 error
= smba_rename(ServerData
,full_source_name
,full_destination_name
);
3575 error
= MapErrnoToIoErr(error
);
3583 FreeMemory(full_source_name
);
3584 FreeMemory(full_destination_name
);
3586 (*error_ptr
) = error
;
3592 /****************************************************************************/
3596 struct InfoData
* id
,
3599 LONG result
= DOSTRUE
;
3602 long num_blocks_free
;
3607 memset(id
,0,sizeof(*id
));
3610 id
->id_DiskState
= ID_WRITE_PROTECTED
;
3612 id
->id_DiskState
= ID_VALIDATED
;
3614 error
= smba_statfs(ServerData
,&block_size
,&num_blocks
,&num_blocks_free
);
3617 SHOWMSG("got the disk data");
3618 SHOWVALUE(block_size
);
3619 SHOWVALUE(num_blocks
);
3620 SHOWVALUE(num_blocks_free
);
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;
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
);
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
;
3677 struct FileLock
* lock
,
3678 struct InfoData
* id
,
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");
3696 (*error_ptr
) = ERROR_NO_DISK
;
3700 result
= Action_DiskInfo(id
,error_ptr
);
3707 /****************************************************************************/
3710 Action_ExamineObject(
3711 struct FileLock
* lock
,
3712 struct FileInfoBlock
* fib
,
3715 LONG result
= DOSFALSE
;
3722 memset(fib
,0,sizeof(*fib
));
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
;
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
;
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
;
3751 struct LockNode
* ln
= (struct LockNode
*)lock
->fl_Key
;
3755 error
= smba_getattr(ln
->ln_File
,&st
);
3758 SHOWMSG("information not available");
3760 error
= MapErrnoToIoErr(error
);
3764 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
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
;
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
;
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
;
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
)
3815 /* Just checking: will the name fit? */
3816 if(name_len
>= sizeof(fib
->fib_FileName
))
3818 error
= ERROR_INVALID_COMPONENT_NAME
;
3822 /* Translate the name of the file/directory from UTF-8
3823 * into AmigaOS ISO 8859-1 (ISO Latin 1) encoding?
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
;
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
);
3853 /* Store the file/directory name in the form expected
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. */
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
;
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
;
3880 fib
->fib_Protection
|= FIBF_PURE
;
3883 fib
->fib_DiskKey
= -1;
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
);
3900 (*error_ptr
) = error
;
3906 /****************************************************************************/
3909 NameIsAcceptable(STRPTR name
,LONG max_len
)
3911 BOOL result
= FALSE
;
3914 /* This takes care of "." and "..". */
3915 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
3918 /* Now for embedded '/', ':' and '\' characters and
3919 * names that just don't want to fit.
3921 while((c
= (*name
++)) != '\0')
3924 if(max_len
== 0 || c
== '/' || c
== ':' || c
== SMB_PATH_SEPARATOR
)
3935 /****************************************************************************/
3938 dir_scan_callback_func_exnext(
3939 struct FileInfoBlock
* fib
,
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
))
3963 name_len
= strlen(name
);
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
)
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
);
3981 ConvertCString(fib
->fib_FileName
,sizeof(fib
->fib_FileName
),name
,name_len
);
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
;
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
;
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();
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
;
4019 fib
->fib_DiskKey
= eof
? -1 : nextpos
;
4027 struct FileLock
* lock
,
4028 struct FileInfoBlock
* fib
,
4031 struct LockNode
* ln
;
4032 LONG result
= DOSFALSE
;
4041 if(fib
->fib_DiskKey
== -1)
4043 SHOWMSG("scanning finished.");
4044 error
= ERROR_NO_MORE_ENTRIES
;
4050 SHOWMSG("invalid lock");
4051 error
= ERROR_INVALID_LOCK
;
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
)
4067 ln
->ln_RestartExamine
= FALSE
;
4070 memset(fib
,0,sizeof(*fib
));
4072 SHOWMSG("calling 'smba_readdir'");
4075 count
= smba_readdir(ln
->ln_File
,offset
,fib
,(smba_callback_t
)dir_scan_callback_func_exnext
);
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
;
4087 else if (count
== (-EIO
))
4089 SHOWMSG("ouch! directory read error");
4090 fib
->fib_DiskKey
= -1;
4092 error
= ERROR_NO_DEFAULT_DIR
;
4097 SHOWMSG("error whilst scanning");
4099 fib
->fib_DiskKey
= -1;
4101 error
= MapErrnoToIoErr(count
);
4109 (*error_ptr
) = error
;
4115 /****************************************************************************/
4119 struct ExAllData
* ec_Last
;
4120 struct ExAllData
* ec_Next
;
4123 struct ExAllControl
* ec_Control
;
4126 BOOL ec_FirstAttempt
;
4130 dir_scan_callback_func_exall(
4131 struct ExAllContext
* ec
,
4138 UBYTE decoded_name
[MAX_FILENAME_LEN
];
4139 BOOL ignore_this_entry
= FALSE
;
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.
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
;
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
;
4181 ULONG type
= ec
->ec_Type
;
4184 size
= (ec
->ec_MinSize
+ strlen(name
)+1 + 3) & ~3UL;
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
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
;
4202 SHOWMSG("try again");
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
);
4220 ed
->ed_Type
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
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
;
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
;
4240 ed
->ed_Prot
|= FIBF_PURE
;
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();
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;
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");
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");
4297 SHOWMSG("registering new entry");
4299 if(ec
->ec_Last
!= NULL
)
4300 ec
->ec_Last
->ed_Next
= 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
);
4317 ec
->ec_FirstAttempt
= FALSE
;
4325 struct FileLock
* lock
,
4326 struct ExAllData
* ed
,
4329 struct ExAllControl
* eac
,
4332 struct ExAllContext ec
;
4333 struct LockNode
* ln
;
4334 LONG result
= DOSFALSE
;
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
;
4356 if(eac
->eac_LastKey
== (ULONG
)-1)
4358 SHOWMSG("scanning finished.");
4359 error
= ERROR_NO_MORE_ENTRIES
;
4365 SHOWMSG("invalid lock");
4366 error
= ERROR_INVALID_LOCK
;
4370 if(type
< ED_NAME
|| type
> ED_OWNER
)
4372 D(("type %ld not supported",type
));
4373 error
= ERROR_BAD_NUMBER
;
4379 memset(&ec
,0,sizeof(ec
));
4382 ec
.ec_BytesLeft
= size
;
4383 ec
.ec_Control
= eac
;
4385 ec
.ec_Error
= ERROR_NO_MORE_ENTRIES
;
4386 ec
.ec_FirstAttempt
= TRUE
;
4392 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Type
);
4397 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Size
);
4402 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Prot
);
4407 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Days
);
4412 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Comment
);
4417 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_OwnerUID
);
4422 ec
.ec_MinSize
= sizeof(struct ExAllData
);
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
)
4440 ln
->ln_RestartExamine
= FALSE
;
4447 SHOWMSG("first invocation");
4449 SHOWMSG("getting file attributes");
4450 error
= smba_getattr(ln
->ln_File
,&st
);
4453 SHOWMSG("didn't work");
4454 error
= MapErrnoToIoErr(error
);
4455 eac
->eac_LastKey
= (ULONG
)-1;
4461 SHOWMSG("lock does not refer to a directory");
4462 error
= ERROR_OBJECT_WRONG_TYPE
;
4463 eac
->eac_LastKey
= (ULONG
)-1;
4468 SHOWMSG("calling 'smba_readdir'");
4471 count
= smba_readdir(ln
->ln_File
,offset
,&ec
,(smba_callback_t
)dir_scan_callback_func_exall
);
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
;
4488 else if (count
== (-EIO
))
4490 SHOWMSG("ouch! directory read error");
4491 eac
->eac_LastKey
= (ULONG
)-1;
4493 error
= ERROR_NO_DEFAULT_DIR
;
4498 SHOWMSG("error whilst scanning");
4499 eac
->eac_LastKey
= (ULONG
)-1;
4501 error
= MapErrnoToIoErr(count
);
4512 SHOWVALUE(eac
->eac_Entries
);
4516 SHOWSTRING(ed
->ed_Name
);
4523 (*error_ptr
) = error
;
4529 /****************************************************************************/
4534 struct FileHandle
* fh
,
4535 struct FileLock
* parent
,
4539 LONG result
= DOSFALSE
;
4540 STRPTR parent_path
= NULL
;
4541 STRPTR full_name
= NULL
;
4542 LONG full_name_size
;
4543 struct FileNode
* fn
= NULL
;
4545 UBYTE name
[MAX_FILENAME_LEN
];
4546 BOOL create_new_file
;
4553 case ACTION_FINDINPUT
:
4554 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name
)));
4557 case ACTION_FINDOUTPUT
:
4558 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name
)));
4561 case ACTION_FINDUPDATE
:
4562 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name
)));
4570 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
4572 parent_name
= ln
->ln_FullName
;
4579 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
;
4609 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
4613 /* Trying to open the root directory? */
4614 if(full_name
== NULL
)
4616 error
= ERROR_OBJECT_WRONG_TYPE
;
4620 fn
= AllocateMemory(sizeof(*fn
));
4623 error
= ERROR_NO_FREE_STORE
;
4627 memset(fn
,0,sizeof(*fn
));
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
);
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
;
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
;
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
;
4679 error
= ERROR_ACTION_NOT_KNOWN
;
4683 /* Create a new file? */
4693 error
= ERROR_DISK_WRITE_PROTECTED
;
4697 parent_path
= AllocateMemory(strlen(full_name
)+3);
4698 if(parent_path
== NULL
)
4700 error
= ERROR_NO_FREE_STORE
;
4704 strcpy(parent_path
,full_name
);
4706 for(i
= strlen(parent_path
)-1 ; i
>= 0 ; i
--)
4708 if(parent_path
[i
] == SMB_PATH_SEPARATOR
)
4712 memmove(&parent_path
[1],&parent_path
[0],strlen(parent_path
)+1);
4716 parent_path
[i
] = '\0';
4718 base_name
= &parent_path
[i
+1];
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
);
4729 error
= MapErrnoToIoErr(error
);
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
);
4742 SHOWMSG("didn't work.");
4746 error
= MapErrnoToIoErr(error
);
4758 /* Now for the remainder... */
4759 error
= smba_open(ServerData
,full_name
,full_name_size
,&fn
->fn_File
);
4762 error
= MapErrnoToIoErr(error
);
4766 fh
->fh_Arg1
= (IPTR
)fn
;
4768 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
4773 if(result
== DOSFALSE
)
4775 FreeMemory(full_name
);
4779 FreeMemory(parent_path
);
4781 (*error_ptr
) = error
;
4787 /****************************************************************************/
4791 struct FileNode
* fn
,
4803 result
= smba_read(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4806 error
= MapErrnoToIoErr(result
);
4811 fn
->fn_Offset
+= result
;
4816 (*error_ptr
) = error
;
4822 /****************************************************************************/
4826 struct FileNode
* fn
,
4831 LONG result
= DOSFALSE
;
4838 error
= ERROR_DISK_WRITE_PROTECTED
;
4844 result
= smba_write(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4847 error
= MapErrnoToIoErr(result
);
4852 fn
->fn_Offset
+= result
;
4857 (*error_ptr
) = error
;
4863 /****************************************************************************/
4867 struct FileNode
* fn
,
4870 Remove((struct Node
*)fn
);
4872 smba_close(fn
->fn_File
);
4873 FreeMemory(fn
->fn_FullName
);
4880 /****************************************************************************/
4884 struct FileNode
* fn
,
4889 LONG previous_position
= fn
->fn_Offset
;
4896 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4901 case OFFSET_BEGINNING
:
4906 case OFFSET_CURRENT
:
4918 error
= ERROR_ACTION_NOT_KNOWN
;
4922 error
= smba_seek (fn
->fn_File
, position
, mode
, (off_t
*) &offset
);
4925 error
= MapErrnoToIoErr(error
);
4931 /* olsen: This is the original implementation. */
4936 error
= smba_getattr(fn
->fn_File
,&st
);
4939 error
= MapErrnoToIoErr(error
);
4943 offset
= fn
->fn_Offset
;
4947 case OFFSET_BEGINNING
:
4952 case OFFSET_CURRENT
:
4959 offset
= st
.size
+ position
;
4964 error
= ERROR_ACTION_NOT_KNOWN
;
4968 if(offset
< 0 || offset
> st
.size
)
4970 error
= ERROR_SEEK_ERROR
;
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
4988 case OFFSET_BEGINNING
:
4993 case OFFSET_CURRENT
:
4995 offset
= fn
->fn_Offset
+ position
;
5000 error
= smba_getattr(fn
->fn_File
,&st
);
5003 error
= MapErrnoToIoErr(error
);
5007 offset
= st
.size
+ position
;
5012 error
= ERROR_ACTION_NOT_KNOWN
;
5018 error
= ERROR_SEEK_ERROR
;
5022 error
= smba_seek (fn
->fn_File
, offset
, 0, (off_t
*) &offset
);
5025 error
= MapErrnoToIoErr(error
);
5033 fn
->fn_Offset
= offset
;
5035 result
= previous_position
;
5039 (*error_ptr
) = error
;
5045 /****************************************************************************/
5049 struct FileNode
* fn
,
5063 error
= ERROR_DISK_WRITE_PROTECTED
;
5067 error
= smba_getattr(fn
->fn_File
,&st
);
5070 error
= MapErrnoToIoErr(error
);
5074 offset
= fn
->fn_Offset
;
5078 case OFFSET_BEGINNING
:
5083 case OFFSET_CURRENT
:
5090 offset
= st
.size
+ position
;
5095 error
= ERROR_ACTION_NOT_KNOWN
;
5101 error
= ERROR_SEEK_ERROR
;
5110 error
= smba_setattr(fn
->fn_File
,&st
);
5113 error
= MapErrnoToIoErr(error
);
5117 if(fn
->fn_Offset
> offset
)
5118 fn
->fn_Offset
= offset
;
5124 (*error_ptr
) = error
;
5130 /****************************************************************************/
5134 struct FileLock
* parent
,
5136 struct DateStamp
* ds
,
5139 LONG result
= DOSFALSE
;
5140 STRPTR full_name
= NULL
;
5141 LONG full_name_size
;
5142 smba_file_t
* file
= NULL
;
5144 UBYTE name
[MAX_FILENAME_LEN
];
5153 error
= ERROR_DISK_WRITE_PROTECTED
;
5161 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5163 parent_name
= ln
->ln_FullName
;
5170 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
);
5198 /* Trying to change the date of the root directory? */
5199 if(full_name
== NULL
)
5201 error
= ERROR_OBJECT_IN_USE
;
5205 SHOWSTRING(full_name
);
5207 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5210 error
= MapErrnoToIoErr(error
);
5214 error
= smba_getattr(file
,&st
);
5217 error
= MapErrnoToIoErr(error
);
5221 seconds
= (ds
->ds_Days
* 24 * 60 + ds
->ds_Minute
) * 60 + (ds
->ds_Tick
/ TICKS_PER_SECOND
);
5225 st
.mtime
= seconds
+ UNIX_TIME_OFFSET
+ GetTimeZoneDelta();
5228 error
= smba_setattr(file
,&st
);
5231 error
= MapErrnoToIoErr(error
);
5239 FreeMemory(full_name
);
5244 (*error_ptr
) = error
;
5250 /****************************************************************************/
5254 struct FileNode
* fn
,
5255 struct FileInfoBlock
* fib
,
5258 LONG result
= DOSFALSE
;
5268 error
= smba_getattr(fn
->fn_File
,&st
);
5271 error
= MapErrnoToIoErr(error
);
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
)
5287 /* Just checking: will the name fit? */
5288 if(name_len
>= sizeof(fib
->fib_FileName
))
5290 error
= ERROR_INVALID_COMPONENT_NAME
;
5294 memset(fib
,0,sizeof(*fib
));
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
;
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
);
5315 ConvertCString(fib
->fib_FileName
,sizeof(fib
->fib_FileName
),name
,name_len
);
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
;
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
;
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();
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
;
5355 (*error_ptr
) = error
;
5361 /****************************************************************************/
5365 struct FileNode
* fn
,
5369 struct LockNode
* ln
= NULL
;
5372 LONG full_name_size
;
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
;
5388 strcpy(full_name
,fn
->fn_FullName
);
5390 for(i
= strlen(full_name
)-1 ; i
>= 0 ; i
--)
5394 strcpy(full_name
,SMB_ROOT_DIR_NAME
);
5397 else if (full_name
[i
] == SMB_PATH_SEPARATOR
)
5399 full_name
[i
] = '\0';
5404 ln
= AllocateMemory(sizeof(*ln
));
5407 error
= ERROR_NO_FREE_STORE
;
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
);
5424 error
= MapErrnoToIoErr(error
);
5428 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5429 result
= MKBADDR(&ln
->ln_FileLock
);
5430 SHOWVALUE(&ln
->ln_FileLock
);
5437 FreeMemory(full_name
);
5440 (*error_ptr
) = error
;
5446 /****************************************************************************/
5450 struct FileNode
* fn
,
5454 struct LockNode
* ln
= NULL
;
5455 STRPTR full_name
= NULL
;
5456 LONG full_name_size
;
5461 if(fn
->fn_Mode
!= SHARED_LOCK
)
5463 error
= ERROR_OBJECT_IN_USE
;
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
;
5478 strcpy(full_name
,fn
->fn_FullName
);
5480 ln
= AllocateMemory(sizeof(*ln
));
5483 error
= ERROR_NO_FREE_STORE
;
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
);
5500 error
= MapErrnoToIoErr(error
);
5504 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5505 result
= MKBADDR(&ln
->ln_FileLock
);
5506 SHOWVALUE(&ln
->ln_FileLock
);
5513 FreeMemory(full_name
);
5516 (*error_ptr
) = error
;
5522 /****************************************************************************/
5526 struct FileHandle
* fh
,
5527 struct FileLock
* fl
,
5530 LONG result
= DOSFALSE
;
5531 struct FileNode
* fn
;
5532 struct LockNode
* ln
;
5539 fn
= AllocateMemory(sizeof(*fn
));
5542 error
= ERROR_NO_FREE_STORE
;
5546 memset(fn
,0,sizeof(*fn
));
5548 ln
= (struct LockNode
*)fl
->fl_Key
;
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
);
5558 fh
->fh_Arg1
= (IPTR
)fn
;
5560 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
5565 (*error_ptr
) = error
;
5571 /****************************************************************************/
5578 LONG result
= DOSFALSE
;
5587 if(NOT VolumeNodeAdded
)
5589 error
= ERROR_OBJECT_IN_USE
;
5595 error
= ERROR_DISK_WRITE_PROTECTED
;
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().
5608 new_name
= AllocVec(1 + len
+ 1,MEMF_ANY
|MEMF_PUBLIC
);
5609 if(new_name
== NULL
)
5611 error
= ERROR_NO_FREE_STORE
;
5616 memcpy(&new_name
[1],&name
[1],len
);
5617 new_name
[len
+1] = '\0';
5621 old_name
= BADDR(VolumeNode
->dol_Name
);
5622 VolumeNode
->dol_Name
= MKBADDR(new_name
);
5628 SendDiskChange(IECLASS_DISKINSERTED
);
5634 (*error_ptr
) = error
;
5640 /****************************************************************************/
5649 LONG result
= DOSFALSE
;
5650 struct FileLock
* fl
= NULL
;
5651 struct FileNode
* fn
= NULL
;
5652 struct LockNode
* ln
= NULL
;
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
;
5667 /* Now obtain the data structures, name and mode
5668 * associated with the object in question.
5670 if(type
== CHANGE_LOCK
)
5673 ln
= (struct LockNode
*)fl
->fl_Key
;
5674 name
= ln
->ln_FullName
;
5675 old_mode
= fl
->fl_Access
;
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
)
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
5700 if(new_mode
== SHARED_LOCK
)
5702 if(type
== CHANGE_LOCK
)
5703 fl
->fl_Access
= new_mode
;
5705 fn
->fn_Mode
= new_mode
;
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
;
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
;
5729 /* There is just one single reference
5730 * to this object; change the mode
5733 if(type
== CHANGE_LOCK
)
5734 fl
->fl_Access
= new_mode
;
5736 fn
->fn_Mode
= new_mode
;
5742 (*error_ptr
) = error
;
5748 /****************************************************************************/
5751 Action_WriteProtect(
5756 LONG result
= DOSFALSE
;
5761 if(flag
== DOSFALSE
)
5765 if(key
!= WriteProtectKey
)
5767 error
= ERROR_INVALID_LOCK
;
5771 WriteProtected
= FALSE
;
5775 SendDiskChange(IECLASS_DISKREMOVED
);
5776 SendDiskChange(IECLASS_DISKINSERTED
);
5782 if(NOT WriteProtected
)
5784 WriteProtected
= TRUE
;
5785 WriteProtectKey
= key
;
5789 SendDiskChange(IECLASS_DISKREMOVED
);
5790 SendDiskChange(IECLASS_DISKINSERTED
);
5795 error
= ERROR_INVALID_LOCK
;
5804 (*error_ptr
) = error
;
5810 /****************************************************************************/
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)
5829 (*error_ptr
) = ERROR_NO_FREE_STORE
;
5836 /****************************************************************************/
5840 struct FileLock
* parent
,
5845 LONG result
= DOSFALSE
;
5846 STRPTR full_name
= NULL
;
5847 LONG full_name_size
;
5848 smba_file_t
* file
= NULL
;
5850 UBYTE name
[MAX_FILENAME_LEN
];
5858 error
= ERROR_DISK_WRITE_PROTECTED
;
5866 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5868 parent_name
= ln
->ln_FullName
;
5875 ConvertBString(sizeof(name
),name
,bcpl_name
);
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
;
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
);
5903 /* Trying to change the comment of the root directory? */
5904 if(full_name
== NULL
)
5906 error
= ERROR_OBJECT_IN_USE
;
5910 SHOWSTRING(full_name
);
5912 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5915 error
= MapErrnoToIoErr(error
);
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
;
5934 FreeMemory(full_name
);
5939 (*error_ptr
) = error
;
5945 /****************************************************************************/
5949 struct FileNode
* fn
,
5956 LONG result
= DOSFALSE
;
5960 /* Sanity checks... */
5961 if (mode
< REC_EXCLUSIVE
|| mode
> REC_SHARED_IMMED
)
5963 error
= ERROR_ACTION_NOT_KNOWN
;
5967 /* Invalid offset, size or integer overflow? */
5968 if (offset
< 0 || length
<= 0 || offset
+ length
< offset
)
5970 error
= ERROR_LOCK_COLLISION
;
5974 if ((mode
== REC_SHARED
) || (mode
== REC_SHARED_IMMED
))
5979 if ((mode
== REC_SHARED_IMMED
) || (mode
== REC_EXCLUSIVE_IMMED
))
5984 if (timeout
> 214748364)
5985 timeout
= ~0; /* wait forever */
5987 timeout
*= 20; /* milliseconds instead of Ticks */
5990 error
= smba_lockrec (fn
->fn_File
, offset
, length
, umode
, 0, (long)timeout
);
5993 error
= MapErrnoToIoErr(error
);
6001 (*error_ptr
) = error
;
6007 /****************************************************************************/
6011 struct FileNode
* fn
,
6016 LONG result
= DOSFALSE
;
6019 /* Sanity checks... */
6020 if(offset
< 0 || length
<= 0 || offset
+ length
< offset
)
6022 error
= ERROR_RECORD_NOT_LOCKED
;
6026 error
= smba_lockrec (fn
->fn_File
, offset
, length
, 2, -1, 0);
6029 error
= MapErrnoToIoErr(error
);
6037 (*error_ptr
) = error
;
6043 /****************************************************************************/
6046 HandleFileSystem(VOID
)
6048 struct Process
* this_process
= (struct Process
*)FindTask(NULL
);
6049 BOOL sign_off
= FALSE
;
6061 /* Raise the Task priority of the file system to 10
6062 * unless it already is running at priority 10 or higher.
6066 old_priority
= this_process
->pr_Task
.tc_Node
.ln_Pri
;
6067 if(old_priority
< 10)
6068 SetTaskPri((struct Task
*)this_process
, 10);
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
;
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
));
6090 if (mn
->mn_Node
.ln_Type
== NT_REPLYMSG
)
6092 LONG max_transmit
= -1;
6093 if(args
.MaxTransmit
!= NULL
)
6094 max_transmit
= (*args
.MaxTransmit
);
6105 (args
.CacheSize
!= NULL
) ? *args
.CacheSize
: 0,
6107 !args
.NetBIOSTransport
/* Use raw SMB transport instead of NetBIOS transport? */
6111 if(!VolumeNodeAdded
&& dp
->dp_Action
!= ACTION_STARTUP
)
6114 res2
= ERROR_NO_DISK
;
6115 ReplyPkt(dp
,res1
,res2
);
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
);
6132 SHOWMSG("ACTION_DIE");
6133 if(IsListEmpty(&FileList
) && IsListEmpty(&LockList
))
6135 SHOWMSG("no locks or files pending; quitting");
6141 SHOWMSG("locks or files still pending; cannot quit yet");
6144 res2
= ERROR_OBJECT_IN_USE
;
6150 case ACTION_CURRENT_VOLUME
:
6151 /* (Ignore) -> VolumeNode */
6153 res1
= (IPTR
)MKBADDR(VolumeNode
);
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
);
6162 case ACTION_RENAME_DISK
:
6165 res1
= Action_RenameDisk((UBYTE
*)BADDR(dp
->dp_Arg1
),&res2
);
6168 case ACTION_FREE_LOCK
:
6171 res1
= Action_FreeLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
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
);
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
);
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
);
6208 case ACTION_COPY_DIR
:
6211 res1
= (IPTR
)Action_CopyDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
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
);
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
);
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
);
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
);
6238 case ACTION_DISK_INFO
:
6239 /* InfoData -> Bool */
6241 Action_DiskInfo((struct InfoData
*)BADDR(dp
->dp_Arg1
),&res2
);
6247 /* FileLock,InfoData -> Bool */
6249 res1
= Action_Info((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct InfoData
*)BADDR(dp
->dp_Arg2
),&res2
);
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
);
6261 res1
= (IPTR
)Action_Parent((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6264 case ACTION_INHIBIT
:
6266 SHOWMSG("ACTION_INHIBIT");
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
);
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
);
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
);
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
);
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
);
6303 /* FileHandle->fh_Arg1 -> Bool */
6305 res1
= Action_End((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6309 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6311 res1
= Action_Seek((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
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
);
6320 case ACTION_WRITE_PROTECT
:
6321 /* Flag,Key -> Bool */
6323 res1
= Action_WriteProtect(dp
->dp_Arg1
,dp
->dp_Arg2
,&res2
);
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
);
6332 case ACTION_IS_FILESYSTEM
:
6334 SHOWMSG("ACTION_IS_FILESYSTEM");
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
);
6344 case ACTION_COPY_DIR_FH
:
6345 /* FileHandle->fh_Arg1 -> Bool */
6347 res1
= (IPTR
)Action_CopyDirFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6350 case ACTION_PARENT_FH
:
6351 /* FileHandle->fh_Arg1 -> Bool */
6353 res1
= (IPTR
)Action_ParentFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
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
);
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
);
6370 case ACTION_EXAMINE_ALL_END
:
6371 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
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
);
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
);
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
;
6403 ReplyPkt(dp
,res1
,res2
);
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
));
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
));
6441 if(signals
& SIGBREAKF_CTRL_C
)
6446 if(IsListEmpty(&FileList
) && IsListEmpty(&LockList
))
6448 SHOWMSG("no locks or files pending; quitting");
6453 SHOWMSG("locks or files still pending; cannot quit yet");
6459 /* Restore the priority of the file system, unless the priority
6460 * has already been changed.
6464 if(old_priority
< 10 && this_process
->pr_Task
.tc_Node
.ln_Pri
== 10)
6465 SetTaskPri((struct Task
*)this_process
, old_priority
);
6470 LocalPrintf("stopped.\n");
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.
6483 strlcpy(char *dst
, const char *src
, size_t siz
)
6486 const char *s
= src
;
6490 /* Copy as many bytes as will fit */
6491 if(n
!= 0 && --n
!= 0)
6495 if(((*d
++) = (*s
++)) == '\0')
6501 /* Not enough room in dst, add NUL and traverse rest of src */
6505 (*d
) = '\0'; /* NUL-terminate dst */
6507 while((*s
++) != '\0')
6511 result
= s
- src
- 1; /* count does not include NUL */
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.
6524 strlcat(char *dst
, const char *src
, size_t siz
)
6527 const char *s
= src
;
6532 /* Find the end of dst and adjust bytes left but don't go past end */
6533 while(n
-- != 0 && (*d
) != '\0')
6541 result
= dlen
+ strlen(s
);
6558 result
= dlen
+ (s
- src
); /* count does not include NUL */