6 * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
8 * Copyright (C) 2000-2016 by Olaf `Olsen' Barthel <obarthel -at- gmx -dot- net>
9 * Copyright (C) 2011-2014,2016-2019, The AROS Development Team
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * cpr smbfs.debug domain=workgroup user=olsen password=... volume=olsen //felix/olsen
28 * cpr smbfs.debug dumpsmb user=guest volume=amiga //windows7-amiga/Users/Public
29 * copy "amiga:Public/Documents/Amiga Files/Shared/dir/Windows-Export/LP2NRFP.h" ram:
30 * smbfs.debug user=guest volume=sicherung //192.168.1.76/sicherung-smb
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 #if !defined(__AROS__)
1672 /* AROS codes use message port from file system process */
1673 DeleteMsgPort(FileSystemPort
);
1675 FileSystemPort
= NULL
;
1678 if(WBStartup
== NULL
&& send_disk_change
)
1679 SendDiskChange(IECLASS_DISKREMOVED
);
1681 #if defined(__amigaos4__)
1685 DropInterface((struct Interface
*)ITimer
);
1689 #endif /* __amigaos4__ */
1691 if(TimerBase
!= NULL
)
1693 CloseDevice((struct IORequest
*)&TimerRequest
);
1697 #if defined(__amigaos4__)
1701 DropInterface((struct Interface
*)ISocket
);
1705 #endif /* __amigaos4__ */
1707 if(SocketBase
!= NULL
)
1709 CloseLibrary(SocketBase
);
1713 #if defined(__amigaos4__)
1717 DropInterface((struct Interface
*)IIcon
);
1721 #endif /* __amigaos4__ */
1723 if(IconBase
!= NULL
)
1725 CloseLibrary(IconBase
);
1731 CloseLocale(Locale
);
1735 #if defined(__amigaos4__)
1739 DropInterface((struct Interface
*)ILocale
);
1743 #endif /* __amigaos4__ */
1745 if(LocaleBase
!= NULL
)
1747 CloseLibrary(LocaleBase
);
1751 if(MemoryPool
!= NULL
)
1753 DeletePool(MemoryPool
);
1760 /****************************************************************************/
1762 /* Allocate all the necessary resources to get going. */
1765 STRPTR opt_password
,
1766 BOOL opt_changecase
,
1767 LONG
* opt_time_zone_offset
,
1768 LONG
* opt_dst_offset
,
1769 STRPTR translation_file
)
1771 BOOL result
= FALSE
;
1777 NewList((struct List
*)&FileList
);
1778 NewList((struct List
*)&LockList
);
1780 MemoryPool
= CreatePool(MEMF_ANY
|MEMF_PUBLIC
,4096,4096);
1781 if(MemoryPool
== NULL
)
1783 ReportError("Could not create memory pool.");
1787 LocaleBase
= OpenLibrary("locale.library",38);
1789 #if defined(__amigaos4__)
1791 if(LocaleBase
!= NULL
)
1793 ILocale
= (struct LocaleIFace
*)GetInterface(LocaleBase
, "main", 1, 0);
1796 CloseLibrary(LocaleBase
);
1801 #endif /* __amigaos4__ */
1803 if(LocaleBase
!= NULL
)
1804 Locale
= OpenLocale(NULL
);
1806 if(opt_time_zone_offset
!= NULL
)
1808 TimeZoneOffset
= (*opt_time_zone_offset
);
1809 OverrideLocaleTimeZone
= TRUE
;
1812 if(opt_dst_offset
!= NULL
)
1813 DSTOffset
= -60 * (*opt_dst_offset
);
1815 memset(&TimerRequest
,0,sizeof(TimerRequest
));
1817 if(OpenDevice(TIMERNAME
,UNIT_VBLANK
,(struct IORequest
*)&TimerRequest
,0) != OK
)
1819 ReportError("Could not open 'timer.device'.");
1823 TimerBase
= (struct Library
*)TimerRequest
.tr_node
.io_Device
;
1825 #if defined(__amigaos4__)
1827 if(TimerBase
!= NULL
)
1829 ITimer
= (struct TimerIFace
*)GetInterface(TimerBase
, "main", 1, 0);
1832 ReportError("Could not open 'timer.device'.");
1837 #endif /* __amigaos4__ */
1839 SocketBase
= OpenLibrary("bsdsocket.library",3);
1841 #if defined(__amigaos4__)
1843 if(SocketBase
!= NULL
)
1845 ISocket
= (struct SocketIFace
*)GetInterface(SocketBase
, "main", 1, 0);
1848 CloseLibrary(SocketBase
);
1853 #endif /* __amigaos4__ */
1855 if(SocketBase
== NULL
)
1857 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
1861 error
= SocketBaseTags(
1862 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno
))), &errno
,
1863 SBTM_SETVAL(SBTC_HERRNOLONGPTR
), &h_errno
,
1864 SBTM_SETVAL(SBTC_LOGTAGPTR
), HandlerName
,
1865 SBTM_SETVAL(SBTC_BREAKMASK
), SIGBREAKF_CTRL_C
,
1869 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error
,amitcp_strerror(error
));
1875 for(i
= 0 ; i
< (LONG
)strlen(opt_password
) ; i
++)
1876 opt_password
[i
] = ToUpper(opt_password
[i
]);
1879 TranslateNames
= FALSE
;
1881 /* Read the translation file, if possible. */
1882 if(translation_file
!= NULL
)
1889 file
= Open(translation_file
,MODE_OLDFILE
);
1892 if(Read(file
,A2M
,256) != 256 ||
1893 Read(file
,M2A
,256) != 256)
1895 msg
= "Could not read translation file";
1903 msg
= "Could not open translation file";
1909 TranslateNames
= TRUE
;
1913 UBYTE description
[100];
1915 Fault(error
,NULL
,description
,sizeof(description
));
1916 for(i
= ((int)strlen(description
)) - 1 ; i
>= 0 ; i
--)
1918 if(description
[i
] == '\n')
1919 description
[i
] = '\0';
1922 ReportError("%s '%s' (%ld, %s).",msg
,translation_file
,error
,description
);
1935 /****************************************************************************/
1938 /* Make connection to server and make a volume for it. */
1946 STRPTR opt_password
,
1947 STRPTR opt_clientname
,
1948 STRPTR opt_servername
,
1950 int opt_max_transmit
,
1953 BOOL result
= FALSE
;
1954 struct DosList
* dl
;
1956 STRPTR actual_volume_name
;
1957 LONG actual_volume_name_len
;
1958 UBYTE name
[MAX_FILENAME_LEN
];
1959 BOOL device_exists
= FALSE
;
1964 error
= smba_start(service
,workgroup
,username
,opt_password
,opt_clientname
,opt_servername
,opt_cachesize
,opt_max_transmit
,opt_raw_smb
,&ServerData
);
1968 /* If a device name was provided, check whether it is
1971 if(device_name
!= NULL
)
1973 len
= strlen(device_name
);
1977 for(i
= 0 ; i
< len
; i
++)
1979 if(device_name
[i
] == '/')
1981 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
1986 /* Lose any trailing colon characters. */
1987 for(i
= len
-1 ; i
>= 0 ; i
--)
1989 if(device_name
[i
] == ':')
1995 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
1999 memcpy(name
,device_name
,len
);
2002 dl
= LockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2004 if(FindDosEntry(dl
,name
,LDF_DEVICES
) != NULL
)
2005 device_exists
= TRUE
;
2009 dl
= LockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2011 /* Find a unique device name. */
2012 for(i
= 0 ; i
< 100 ; i
++)
2014 SPrintf(name
,"SMBFS%ld",(long)i
);
2016 device_exists
= (BOOL
)(FindDosEntry(dl
,name
,LDF_DEVICES
) != NULL
);
2017 if(NOT device_exists
)
2027 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2029 ReportError("Device name '%s:' is already taken.",device_name
);
2033 /* Finally, create the device node. */
2034 DeviceNode
= MakeDosEntry(name
,DLT_DEVICE
);
2035 if(DeviceNode
== NULL
)
2037 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2039 ReportError("Could not create device node.");
2043 DeviceNode
->dol_Task
= FileSystemPort
;
2045 /* Examine the volume name; make sure that it is
2048 if(volume_name
== NULL
)
2049 actual_volume_name
= device_name
;
2051 actual_volume_name
= volume_name
;
2053 actual_volume_name_len
= strlen(actual_volume_name
);
2054 if(actual_volume_name_len
> 255)
2055 actual_volume_name_len
= 255;
2057 for(i
= 0 ; i
< actual_volume_name_len
; i
++)
2059 if(actual_volume_name
[i
] == '/')
2061 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2063 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
2068 /* Lose any trailing colon characters. */
2069 for(i
= actual_volume_name_len
-1 ; i
>= 0 ; i
--)
2071 if(actual_volume_name
[i
] == ':')
2072 actual_volume_name_len
= i
;
2075 if(actual_volume_name_len
== 0)
2077 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2079 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
2083 /* Now, finally, take care of the volume name. */
2084 memcpy(name
,actual_volume_name
,actual_volume_name_len
);
2085 name
[actual_volume_name_len
] = '\0';
2087 VolumeNode
= MakeDosEntry(name
,DLT_VOLUME
);
2088 if(VolumeNode
== NULL
)
2090 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2092 ReportError("Could not create volume node.");
2096 VolumeNode
->dol_Task
= FileSystemPort
;
2097 DateStamp(&VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
);
2098 VolumeNode
->dol_misc
.dol_volume
.dol_DiskType
= ID_DOS_DISK
;
2100 if(DeviceNode
!= NULL
)
2102 AddDosEntry(DeviceNode
);
2104 DeviceNodeAdded
= TRUE
;
2107 /* Note: we always need the volume node to make some file
2108 * system operations safe (e.g. Lock()), but we may
2109 * not always need to make it visible.
2111 if(volume_name
!= NULL
&& VolumeNode
!= NULL
)
2113 AddDosEntry(VolumeNode
);
2115 VolumeNodeAdded
= TRUE
;
2118 /* And that concludes the mounting operation. */
2119 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2121 /* Tell Workbench and friends to update their volume lists. */
2123 SendDiskChange(IECLASS_DISKINSERTED
);
2133 /****************************************************************************/
2135 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2137 ConvertBString(LONG max_len
,STRPTR cstring
,APTR bstring
)
2139 STRPTR from
= bstring
;
2141 #if !defined(AROS_FAST_BSTR)
2150 memcpy(cstring
,from
+1,len
);
2152 cstring
[len
] = '\0';
2155 /* Convert a NUL terminated 'C' string into a BCPL string. */
2157 ConvertCString(APTR bstring
,LONG max_len
,STRPTR cstring
,LONG len
)
2159 STRPTR to
= bstring
;
2164 #if !defined(AROS_FAST_BSTR)
2167 memcpy(to
,cstring
,len
);
2168 #if defined(AROS_FAST_BSTR)
2173 /****************************************************************************/
2175 /* Build the fully qualified name of a file or directory in reference
2176 * to the name of the parent directory. This takes care of all the
2177 * special cases, such as the root directory. The result will be converted
2178 * to be in a form suitable for use with the SMB file sharing service.
2184 STRPTR
* result_ptr
,
2185 LONG
* result_size_ptr
)
2194 SHOWSTRING(parent_name
);
2197 (*result_ptr
) = NULL
;
2199 /* Throw everything left of the colon away. */
2202 for(i
= 0 ; i
< (LONG
)strlen(name
) ; i
++)
2212 /* Now, how much room is needed for the complete
2213 * path to fit into a buffer?
2217 if(parent_name
!= NULL
)
2218 len
+= strlen(parent_name
) + 1;
2221 len
+= strlen(name
) + 1;
2223 if(len
< SMB_MAXNAMELEN
)
2224 len
= SMB_MAXNAMELEN
;
2228 buffer
= AllocateMemory(size
);
2231 error
= ERROR_NO_FREE_STORE
;
2235 /* Start by filling in the path name. */
2236 if(parent_name
!= NULL
)
2238 /* Skip any excess separators. */
2239 while((*parent_name
) == SMB_PATH_SEPARATOR
)
2242 buffer
[0] = SMB_PATH_SEPARATOR
;
2243 strcpy(&buffer
[1],parent_name
);
2247 strcpy(buffer
,SMB_ROOT_DIR_NAME
);
2250 /* If there's a name to add, do just that. */
2258 buffer_len
= strlen(buffer
);
2259 name_len
= strlen(name
);
2267 /* Extract the next path name segment. */
2268 for(i
= segment_start
; i
<= name_len
; i
++)
2272 segment_len
= i
- segment_start
;
2275 else if (name
[i
] == '/')
2277 segment_len
= i
- segment_start
+ 1;
2282 /* We're finished if there are no further
2283 * path name segments to take care of.
2285 if(segment_len
== 0)
2287 buffer
[buffer_len
] = '\0';
2291 /* A single slash indicates that we need to move up
2292 * to the parent directory, if any.
2294 if(segment_len
== 1 && name
[segment_start
] == '/')
2296 /* Is this already the root directory name? */
2306 /* Skip the last path component. */
2307 for(i
= 1 ; i
<= buffer_len
; i
++)
2311 /* We just skipped the first path
2312 * component following the root
2313 * directory name. We preserve
2314 * the first character since it
2315 * refers to the root directory.
2320 else if (buffer
[buffer_len
-i
] == SMB_PATH_SEPARATOR
)
2322 /* This removes both the path separator and
2323 * the name following it.
2333 /* Add a proper separator character if
2336 if(buffer_len
> 0 && buffer
[buffer_len
-1] != SMB_PATH_SEPARATOR
)
2337 buffer
[buffer_len
++] = SMB_PATH_SEPARATOR
;
2339 /* Find out how many characters are in that name; this
2340 * excludes the terminating slash.
2342 if(name
[segment_start
+ segment_len
- 1] == '/')
2343 len
= segment_len
- 1;
2347 memcpy(&buffer
[buffer_len
],&name
[segment_start
],len
);
2351 segment_start
+= segment_len
;
2355 (*result_ptr
) = buffer
;
2356 (*result_size_ptr
) = size
;
2369 /****************************************************************************/
2373 struct FileSysStartupMsg
* fssm
,
2374 struct DosList
* device_node
,
2377 LONG cache_size
= 0;
2378 LONG max_transmit
= -1;
2379 char env_workgroup_name
[17];
2380 char env_user_name
[64];
2381 char env_password
[64];
2384 char env_service_name
[17];
2386 BOOL result
= DOSTRUE
;
2391 DeviceNode
= device_node
;
2392 device_node
->dol_Task
= FileSystemPort
;
2394 memset(&args
,0,sizeof(args
));
2396 Parameters
= AllocDosObject(DOS_RDARGS
, NULL
);
2397 if(Parameters
== NULL
)
2400 ((struct DosEnvec
*)BADDR(fssm
->fssm_Environ
))->de_Control
;
2401 Parameters
->RDA_Source
.CS_Buffer
= control
;
2402 Parameters
->RDA_Source
.CS_Length
= strlen(control
);
2403 Parameters
= ReadArgs(cmd_template
,(IPTR
*)&args
,Parameters
);
2404 if(Parameters
== NULL
)
2409 if(args
.Workgroup
== NULL
)
2411 if(GetVar("smbfs_domain",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0 ||
2412 GetVar("smbfs_workgroup",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0)
2414 args
.Workgroup
= env_workgroup_name
;
2418 args
.Workgroup
= "WORKGROUP";
2422 if(args
.UserName
== NULL
)
2424 if(GetVar("smbfs_user",env_user_name
,sizeof(env_user_name
),0) > 0 ||
2425 GetVar("smbfs_username",env_user_name
,sizeof(env_user_name
),0) > 0)
2427 args
.UserName
= env_user_name
;
2431 if(args
.Password
== NULL
)
2433 if(GetVar("smbfs_password",env_password
,sizeof(env_password
),0) > 0)
2434 args
.Password
= env_password
;
2437 if(args
.Service
== NULL
)
2439 if(GetVar("smbfs_service",env_service_name
,sizeof(env_service_name
),0) > 0 ||
2440 GetVar("smbfs_share",env_service_name
,sizeof(env_service_name
),0) > 0)
2442 args
.Service
= env_service_name
;
2446 ReportError("Required 'SERVICE' parameter was not provided.");
2451 if(args
.CacheSize
!= NULL
)
2452 cache_size
= (*args
.CacheSize
);
2454 if(args
.MaxTransmit
!= NULL
)
2455 max_transmit
= (*args
.MaxTransmit
);
2457 /* Use the default if no user name is given. */
2458 if(args
.UserName
== NULL
)
2459 args
.UserName
= "GUEST";
2461 /* Volume name defaults to share name. */
2462 if(args
.VolumeName
== NULL
)
2463 args
.VolumeName
= FilePart(args
.Service
);
2465 /* Use the default if no device or volume name is given. */
2466 if(args
.DeviceName
== NULL
&& args
.VolumeName
== NULL
)
2467 args
.DeviceName
= "SMBFS";
2469 /* UTF8 file name translation disables code-page based translation. */
2471 args
.TranslationFile
= NULL
;
2473 CaseSensitive
= (BOOL
)args
.CaseSensitive
;
2474 OmitHidden
= (BOOL
)args
.OmitHidden
;
2475 TranslateUTF8
= (BOOL
)args
.UTF8
;
2477 /* Configure the debugging options. */
2478 if(args
.DebugLevel
!= NULL
)
2479 SETDEBUGLEVEL(*args
.DebugLevel
);
2483 /* Enable SMB packet decoding, but only if not started from Workbench. */
2484 #if defined(DUMP_SMB)
2487 control_smb_dump(TRUE
);
2489 #endif /* DUMP_SMB */
2491 D(("%s (%s)",VERS
,DATE
));
2496 args
.TimeZoneOffset
,
2498 args
.TranslationFile
))
2511 !args
.NetBIOSTransport
/* Use raw SMB transport instead of NetBIOS transport? */
2521 (*error_ptr
) = error
;
2527 /****************************************************************************/
2531 struct FileLock
* parent
,
2535 STRPTR full_name
= NULL
;
2536 LONG full_name_size
;
2538 BOOL cleanup
= TRUE
;
2539 struct LockNode
* ln
= NULL
;
2548 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2550 parent_name
= parent_ln
->ln_FullName
;
2557 error
= BuildFullName(parent_name
,"/",&full_name
,&full_name_size
);
2561 /* Check if we ended up having to return the parent of
2562 * the root directory. This is indicated by a NULL
2563 * name pointer and a zero error code.
2565 if(full_name
== NULL
)
2568 ln
= AllocateMemory(sizeof(*ln
));
2571 error
= ERROR_NO_FREE_STORE
;
2575 memset(ln
,0,sizeof(*ln
));
2577 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2578 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
2579 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2580 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2581 ln
->ln_FullName
= full_name
;
2583 SHOWSTRING(full_name
);
2585 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2588 error
= MapErrnoToIoErr(error
);
2592 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2593 result
= MKBADDR(&ln
->ln_FileLock
);
2595 SHOWVALUE(&ln
->ln_FileLock
);
2601 FreeMemory(full_name
);
2605 (*error_ptr
) = error
;
2611 /****************************************************************************/
2613 /* Find the lock node corresponding to a given name,
2614 * starting from node start. (if node, this one is skipped)
2616 STATIC
struct LockNode
*
2617 FindNextLockNode(STRPTR name
,struct LockNode
* last_ln
)
2619 struct LockNode
* result
= NULL
;
2620 struct LockNode
* ln
;
2621 struct LockNode
* start
;
2624 start
= (struct LockNode
*)last_ln
->ln_MinNode
.mln_Succ
;
2626 start
= (struct LockNode
*)LockList
.mlh_Head
;
2629 ln
->ln_MinNode
.mln_Succ
!= NULL
;
2630 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
2632 if(CompareNames(name
,ln
->ln_FullName
) == SAME
)
2642 /****************************************************************************/
2645 Action_DeleteObject(
2646 struct FileLock
* parent
,
2650 LONG result
= DOSFALSE
;
2651 STRPTR full_name
= NULL
;
2652 LONG full_name_size
;
2653 smba_file_t
* file
= NULL
;
2655 STRPTR full_parent_name
= NULL
;
2656 UBYTE name
[MAX_FILENAME_LEN
];
2657 struct LockNode
* ln
;
2665 error
= ERROR_DISK_WRITE_PROTECTED
;
2673 ln
= (struct LockNode
*)parent
->fl_Key
;
2675 parent_name
= ln
->ln_FullName
;
2682 /* Name string, as given in the DOS packet, is in
2683 * BCPL format and needs to be converted into
2686 ConvertBString(sizeof(name
),name
,bcpl_name
);
2688 /* Translate the Amiga file name into UTF-8 encoded form? */
2691 UBYTE encoded_name
[MAX_FILENAME_LEN
];
2692 int encoded_name_len
;
2693 LONG name_len
= strlen(name
);
2695 /* Figure out how long the UTF-8 version will become. */
2696 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
2698 /* Encoding error occured, or the resulting name is longer than the buffer will hold? */
2699 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
2701 error
= ERROR_INVALID_COMPONENT_NAME
;
2705 /* Repeat the encoding process, writing the result to the
2706 * replacement name buffer now.
2708 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
2710 /* Copy it back to the conversion buffer (which is not terribly efficient, though). */
2711 strlcpy(name
,encoded_name
,sizeof(name
));
2713 /* Translate the Amiga file name using a translation table? */
2714 else if (TranslateNames
)
2716 TranslateCName(name
,A2M
);
2719 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2723 /* Trying to delete the root directory, are you kidding? */
2724 if(full_name
== NULL
)
2726 error
= ERROR_OBJECT_WRONG_TYPE
;
2730 /* We need to find this file's parent directory, so that
2731 * in case the directory contents are currently being
2732 * examined, that process is restarted.
2734 full_parent_name
= AllocateMemory(strlen(full_name
)+3);
2735 if(full_parent_name
== NULL
)
2737 error
= ERROR_NO_FREE_STORE
;
2741 strcpy(full_parent_name
,full_name
);
2743 /* Build the parent object name - Piru */
2744 if (full_parent_name
[0] != '\0')
2748 i
= strlen(full_parent_name
) - 1;
2749 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2752 for ( ; i
>= 0 ; i
--)
2754 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2756 full_parent_name
[i
] = '\0';
2762 /* NOTE: Mark all locks to this object as restart, not just first
2765 while ((ln
= FindNextLockNode(full_parent_name
, ln
)) != NULL
)
2766 ln
->ln_RestartExamine
= TRUE
;
2768 ln
= FindLockNode(full_parent_name
,NULL
);
2770 ln
->ln_RestartExamine
= TRUE
;
2772 FreeMemory(full_parent_name
);
2773 full_parent_name
= NULL
;
2775 SHOWSTRING(full_name
);
2777 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
2780 error
= MapErrnoToIoErr(error
);
2784 error
= smba_getattr(file
,&st
);
2787 error
= MapErrnoToIoErr(error
);
2796 SHOWMSG("removing a directory");
2798 error
= smba_rmdir(ServerData
,full_name
);
2803 /* This is a little bit difficult to justify since
2804 * the error code may indicate a different cause,
2805 * but in practice 'EACCES' seems to be returned
2806 * if the directory to remove is not empty.
2808 if(error
== (-EACCES
))
2809 error
= ERROR_DIRECTORY_NOT_EMPTY
;
2811 error
= MapErrnoToIoErr(error
);
2818 SHOWMSG("removing a file");
2820 error
= smba_remove(ServerData
,full_name
);
2825 error
= MapErrnoToIoErr(error
);
2836 FreeMemory(full_name
);
2837 FreeMemory(full_parent_name
);
2842 (*error_ptr
) = error
;
2848 /****************************************************************************/
2852 struct FileLock
* parent
,
2857 STRPTR full_name
= NULL
;
2858 LONG full_name_size
;
2859 struct LockNode
* ln
= NULL
;
2861 STRPTR dir_name
= NULL
;
2862 smba_file_t
* dir
= NULL
;
2864 UBYTE name
[MAX_FILENAME_LEN
];
2872 error
= ERROR_DISK_WRITE_PROTECTED
;
2880 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2882 parent_name
= parent_ln
->ln_FullName
;
2889 ConvertBString(sizeof(name
),name
,bcpl_name
);
2893 UBYTE encoded_name
[MAX_FILENAME_LEN
];
2894 int encoded_name_len
;
2895 LONG name_len
= strlen(name
);
2897 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
2898 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
2900 error
= ERROR_INVALID_COMPONENT_NAME
;
2904 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
2906 strlcpy(name
,encoded_name
,sizeof(name
));
2908 else if (TranslateNames
)
2910 TranslateCName(name
,A2M
);
2913 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2917 /* Trying to overwrite the root directory, are you kidding? */
2918 if(full_name
== NULL
)
2920 error
= ERROR_OBJECT_IN_USE
;
2924 dir_name
= AllocateMemory(strlen(full_name
)+3);
2925 if(dir_name
== NULL
)
2927 error
= ERROR_NO_FREE_STORE
;
2931 strcpy(dir_name
,full_name
);
2933 for(i
= strlen(dir_name
)-1 ; i
>= 0 ; i
--)
2935 if(dir_name
[i
] == SMB_PATH_SEPARATOR
)
2939 memmove(&dir_name
[1],&dir_name
[0],strlen(dir_name
)+1);
2945 base_name
= &dir_name
[i
+1];
2950 ln
= AllocateMemory(sizeof(*ln
));
2953 error
= ERROR_NO_FREE_STORE
;
2957 memset(ln
,0,sizeof(*ln
));
2959 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2960 ln
->ln_FileLock
.fl_Access
= EXCLUSIVE_LOCK
;
2961 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2962 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2963 ln
->ln_FullName
= full_name
;
2965 error
= smba_open(ServerData
,dir_name
,strlen(full_name
)+3,&dir
);
2968 error
= MapErrnoToIoErr(error
);
2972 error
= smba_mkdir(dir
,base_name
);
2975 error
= MapErrnoToIoErr(error
);
2982 SHOWSTRING(full_name
);
2984 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2987 error
= MapErrnoToIoErr(error
);
2991 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2992 result
= MKBADDR(&ln
->ln_FileLock
);
2993 SHOWVALUE(&ln
->ln_FileLock
);
3000 FreeMemory(dir_name
);
3004 FreeMemory(full_name
);
3008 (*error_ptr
) = error
;
3014 /****************************************************************************/
3017 Action_LocateObject(
3018 struct FileLock
* parent
,
3024 STRPTR full_name
= NULL
;
3025 LONG full_name_size
;
3026 struct LockNode
* ln
= NULL
;
3028 UBYTE name
[MAX_FILENAME_LEN
];
3037 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
3039 parent_name
= parent_ln
->ln_FullName
;
3046 ConvertBString(sizeof(name
),name
,bcpl_name
);
3050 UBYTE encoded_name
[MAX_FILENAME_LEN
];
3051 int encoded_name_len
;
3052 LONG name_len
= strlen(name
);
3054 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
3055 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
3057 error
= ERROR_INVALID_COMPONENT_NAME
;
3061 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
3063 strlcpy(name
,encoded_name
,sizeof(name
));
3065 else if (TranslateNames
)
3067 TranslateCName(name
,A2M
);
3070 if(IsReservedName(FilePart(name
)))
3072 error
= ERROR_OBJECT_NOT_FOUND
;
3076 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3080 /* Trying to get a lock on the root directory's parent?
3083 if(full_name
== NULL
)
3086 ln
= AllocateMemory(sizeof(*ln
));
3089 error
= ERROR_NO_FREE_STORE
;
3093 memset(ln
,0,sizeof(*ln
));
3095 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
3096 ln
->ln_FileLock
.fl_Access
= (mode
!= EXCLUSIVE_LOCK
) ? SHARED_LOCK
: EXCLUSIVE_LOCK
;
3097 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
3098 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
3099 ln
->ln_FullName
= full_name
;
3101 error
= CheckAccessModeCollision(full_name
,ln
->ln_FileLock
.fl_Access
);
3105 SHOWSTRING(full_name
);
3107 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3110 error
= MapErrnoToIoErr(error
);
3114 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3115 result
= MKBADDR(&ln
->ln_FileLock
);
3116 SHOWVALUE(&ln
->ln_FileLock
);
3122 FreeMemory(full_name
);
3126 (*error_ptr
) = error
;
3132 /****************************************************************************/
3136 struct FileLock
* lock
,
3140 STRPTR full_name
= NULL
;
3141 LONG full_name_size
;
3142 struct LockNode
* ln
= NULL
;
3151 if(lock
!= NULL
&& lock
->fl_Access
!= SHARED_LOCK
)
3153 SHOWMSG("cannot duplicate exclusive lock");
3154 error
= ERROR_OBJECT_IN_USE
;
3158 ln
= AllocateMemory(sizeof(*ln
));
3161 error
= ERROR_NO_FREE_STORE
;
3165 memset(ln
,0,sizeof(*ln
));
3169 struct LockNode
* source
= (struct LockNode
*)lock
->fl_Key
;
3171 source_name
= source
->ln_FullName
;
3172 source_mode
= source
->ln_FileLock
.fl_Access
;
3176 source_name
= SMB_ROOT_DIR_NAME
;
3177 source_mode
= SHARED_LOCK
;
3180 full_name_size
= strlen(source_name
)+3;
3181 if(full_name_size
< SMB_MAXNAMELEN
+1)
3182 full_name_size
= SMB_MAXNAMELEN
+1;
3184 full_name
= AllocateMemory(full_name_size
);
3185 if(full_name
== NULL
)
3187 error
= ERROR_NO_FREE_STORE
;
3191 strcpy(full_name
,source_name
);
3193 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
3194 ln
->ln_FileLock
.fl_Access
= source_mode
;
3195 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
3196 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
3197 ln
->ln_FullName
= full_name
;
3199 SHOWSTRING(full_name
);
3201 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3204 error
= MapErrnoToIoErr(error
);
3208 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3209 result
= MKBADDR(&ln
->ln_FileLock
);
3210 SHOWVALUE(&ln
->ln_FileLock
);
3216 FreeMemory(full_name
);
3220 (*error_ptr
) = error
;
3226 /****************************************************************************/
3230 struct FileLock
* lock
,
3233 LONG result
= DOSTRUE
;
3234 struct LockNode
* ln
;
3244 ln
= (struct LockNode
*)lock
->fl_Key
;
3246 Remove((struct Node
*)ln
);
3248 smba_close(ln
->ln_File
);
3249 FreeMemory(ln
->ln_FullName
);
3254 (*error_ptr
) = error
;
3260 /****************************************************************************/
3264 struct FileLock
* lock1
,
3265 struct FileLock
* lock2
,
3268 LONG result
= DOSFALSE
;
3280 struct LockNode
* ln
= (struct LockNode
*)lock1
->fl_Key
;
3282 name1
= ln
->ln_FullName
;
3286 name1
= SMB_ROOT_DIR_NAME
;
3291 struct LockNode
* ln
= (struct LockNode
*)lock2
->fl_Key
;
3293 name2
= ln
->ln_FullName
;
3297 name2
= SMB_ROOT_DIR_NAME
;
3303 if(Stricmp(name1
,name2
) == SAME
)
3306 (*error_ptr
) = error
;
3312 /****************************************************************************/
3316 struct FileLock
* parent
,
3321 LONG result
= DOSFALSE
;
3322 STRPTR full_name
= NULL
;
3323 LONG full_name_size
;
3324 smba_file_t
* file
= NULL
;
3326 UBYTE name
[MAX_FILENAME_LEN
];
3334 error
= ERROR_DISK_WRITE_PROTECTED
;
3342 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
3344 parent_name
= ln
->ln_FullName
;
3351 ConvertBString(sizeof(name
),name
,bcpl_name
);
3355 UBYTE encoded_name
[MAX_FILENAME_LEN
];
3356 int encoded_name_len
;
3357 LONG name_len
= strlen(name
);
3359 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
3360 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
3362 error
= ERROR_INVALID_COMPONENT_NAME
;
3366 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
3368 strlcpy(name
,encoded_name
,sizeof(name
));
3370 else if (TranslateNames
)
3372 TranslateCName(name
,A2M
);
3375 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3379 /* Trying to change the protection bits of the root
3380 * directory, are you kidding?
3382 if(full_name
== NULL
)
3384 error
= ERROR_OBJECT_WRONG_TYPE
;
3388 SHOWSTRING(full_name
);
3390 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
3393 error
= MapErrnoToIoErr(error
);
3397 memset(&st
,0,sizeof(st
));
3399 mask
^= FIBF_READ
| FIBF_WRITE
| FIBF_EXECUTE
| FIBF_DELETE
;
3406 if((mask
& (FIBF_WRITE
|FIBF_DELETE
)) != (FIBF_WRITE
|FIBF_DELETE
))
3408 SHOWMSG("write protection enabled");
3413 SHOWMSG("write protection disabled");
3416 /* Careful: the 'archive' attribute has exactly the opposite
3417 * meaning in the Amiga and the SMB worlds.
3419 st
.is_archive
= ((mask
& FIBF_ARCHIVE
) == 0);
3421 /* The 'system' attribute is associated with the 'pure' bit for now. */
3422 st
.is_system
= ((mask
& FIBF_PURE
) != 0);
3424 error
= smba_setattr(file
,&st
);
3427 error
= MapErrnoToIoErr(error
);
3435 FreeMemory(full_name
);
3440 (*error_ptr
) = error
;
3446 /****************************************************************************/
3449 Action_RenameObject(
3450 struct FileLock
* source_lock
,
3451 APTR source_bcpl_name
,
3452 struct FileLock
* destination_lock
,
3453 APTR destination_bcpl_name
,
3456 struct LockNode
* ln
;
3457 LONG result
= DOSFALSE
;
3458 STRPTR full_source_name
= NULL
;
3459 LONG full_source_name_size
;
3460 STRPTR full_destination_name
= NULL
;
3461 LONG full_destination_name_size
;
3462 UBYTE name
[MAX_FILENAME_LEN
];
3470 error
= ERROR_DISK_WRITE_PROTECTED
;
3474 SHOWVALUE(source_lock
);
3475 SHOWVALUE(destination_lock
);
3477 if(source_lock
!= NULL
)
3479 ln
= (struct LockNode
*)source_lock
->fl_Key
;
3481 parent_name
= ln
->ln_FullName
;
3488 ConvertBString(sizeof(name
),name
,source_bcpl_name
);
3492 UBYTE encoded_name
[MAX_FILENAME_LEN
];
3493 int encoded_name_len
;
3494 LONG name_len
= strlen(name
);
3496 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
3497 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
3499 error
= ERROR_INVALID_COMPONENT_NAME
;
3503 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
3505 strlcpy(name
,encoded_name
,sizeof(name
));
3507 else if (TranslateNames
)
3509 TranslateCName(name
,A2M
);
3512 error
= BuildFullName(parent_name
,name
,&full_source_name
,&full_source_name_size
);
3516 /* Trying to rename the root directory, are you kidding? */
3517 if(full_source_name
== NULL
)
3519 error
= ERROR_OBJECT_IN_USE
;
3523 if(destination_lock
!= NULL
)
3525 ln
= (struct LockNode
*)destination_lock
->fl_Key
;
3527 parent_name
= ln
->ln_FullName
;
3534 ConvertBString(sizeof(name
),name
,destination_bcpl_name
);
3538 UBYTE encoded_name
[MAX_FILENAME_LEN
];
3539 int encoded_name_len
;
3540 LONG name_len
= strlen(name
);
3542 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
3543 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
3545 error
= ERROR_INVALID_COMPONENT_NAME
;
3549 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
3551 strlcpy(name
,encoded_name
,sizeof(name
));
3553 else if (TranslateNames
)
3555 TranslateCName(name
,A2M
);
3558 error
= BuildFullName(parent_name
,name
,&full_destination_name
,&full_destination_name_size
);
3562 /* Trying to rename the root directory, are you kidding? */
3563 if(full_destination_name
== NULL
)
3565 error
= ERROR_OBJECT_IN_USE
;
3569 error
= NameAlreadyInUse(full_source_name
);
3573 error
= NameAlreadyInUse(full_destination_name
);
3577 SHOWSTRING(full_source_name
);
3578 SHOWSTRING(full_destination_name
);
3580 error
= smba_rename(ServerData
,full_source_name
,full_destination_name
);
3583 error
= MapErrnoToIoErr(error
);
3591 FreeMemory(full_source_name
);
3592 FreeMemory(full_destination_name
);
3594 (*error_ptr
) = error
;
3600 /****************************************************************************/
3604 struct InfoData
* id
,
3607 LONG result
= DOSTRUE
;
3610 long num_blocks_free
;
3615 memset(id
,0,sizeof(*id
));
3618 id
->id_DiskState
= ID_WRITE_PROTECTED
;
3620 id
->id_DiskState
= ID_VALIDATED
;
3622 error
= smba_statfs(ServerData
,&block_size
,&num_blocks
,&num_blocks_free
);
3625 SHOWMSG("got the disk data");
3626 SHOWVALUE(block_size
);
3627 SHOWVALUE(num_blocks
);
3628 SHOWVALUE(num_blocks_free
);
3633 if(block_size
< 512)
3635 num_blocks
/= (512 / block_size
);
3636 num_blocks_free
/= (512 / block_size
);
3638 else if (block_size
> 512)
3640 num_blocks
*= (block_size
/ 512);
3641 num_blocks_free
*= (block_size
/ 512);
3644 id
->id_NumBlocks
= num_blocks
;
3645 id
->id_NumBlocksUsed
= num_blocks
- num_blocks_free
;
3646 id
->id_BytesPerBlock
= 512;
3647 id
->id_DiskType
= ID_DOS_DISK
;
3648 id
->id_VolumeNode
= MKBADDR(VolumeNode
);
3649 id
->id_InUse
= NOT (IsListEmpty(&FileList
) && IsListEmpty(&LockList
));
3651 if(id
->id_NumBlocks
== 0)
3652 id
->id_NumBlocks
= 1;
3654 if(id
->id_NumBlocksUsed
== 0)
3655 id
->id_NumBlocksUsed
= 1;
3659 SHOWMSG("could not get any disk data");
3661 id
->id_NumBlocks
= 1;
3662 id
->id_NumBlocksUsed
= 1;
3663 id
->id_BytesPerBlock
= 512;
3664 id
->id_DiskType
= ID_NO_DISK_PRESENT
;
3666 error
= MapErrnoToIoErr(error
);
3670 SHOWVALUE(id
->id_NumBlocks
);
3671 SHOWVALUE(id
->id_NumBlocksUsed
);
3672 SHOWVALUE(id
->id_BytesPerBlock
);
3673 SHOWVALUE(id
->id_DiskType
);
3674 SHOWVALUE(id
->id_VolumeNode
);
3675 SHOWVALUE(id
->id_InUse
);
3677 (*error_ptr
) = error
;
3685 struct FileLock
* lock
,
3686 struct InfoData
* id
,
3695 /* We need to check if the lock matches the volume node. However,
3696 * a NULL lock is valid, too.
3698 if(lock
!= NULL
&& lock
->fl_Volume
!= MKBADDR(VolumeNode
))
3700 SHOWMSG("volume node does not match");
3704 (*error_ptr
) = ERROR_NO_DISK
;
3708 result
= Action_DiskInfo(id
,error_ptr
);
3715 /****************************************************************************/
3718 Action_ExamineObject(
3719 struct FileLock
* lock
,
3720 struct FileInfoBlock
* fib
,
3723 LONG result
= DOSFALSE
;
3730 memset(fib
,0,sizeof(*fib
));
3734 #if !defined(__AROS__)
3735 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3736 LONG len
= volume_name
[0];
3738 memcpy(fib
->fib_FileName
+1,volume_name
+1,len
);
3739 fib
->fib_FileName
[0] = len
;
3741 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3742 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3744 memcpy(fib
->fib_FileName
+ 1, volume_name
, len
);
3745 fib
->fib_FileName
[0] = len
;
3747 SHOWMSG("ZERO root lock");
3749 fib
->fib_DirEntryType
= ST_ROOT
;
3750 fib
->fib_EntryType
= ST_ROOT
;
3751 fib
->fib_NumBlocks
= 1;
3752 fib
->fib_Date
= VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
;
3753 fib
->fib_DiskKey
= -1;
3754 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3755 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3759 struct LockNode
* ln
= (struct LockNode
*)lock
->fl_Key
;
3763 error
= smba_getattr(ln
->ln_File
,&st
);
3766 SHOWMSG("information not available");
3768 error
= MapErrnoToIoErr(error
);
3772 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
3776 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
3777 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
3778 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
3780 SHOWSTRING(ln
->ln_FullName
);
3782 if(strcmp(ln
->ln_FullName
,SMB_ROOT_DIR_NAME
) == SAME
)
3784 #if !defined(__AROS__)
3785 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3786 LONG len
= volume_name
[0];
3788 memcpy(fib
->fib_FileName
+1,volume_name
+1,len
);
3789 fib
->fib_FileName
[0] = len
;
3791 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3792 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3794 memcpy(fib
->fib_FileName
+ 1, volume_name
, len
);
3795 fib
->fib_FileName
[0] = len
;
3797 SHOWMSG("root lock");
3799 fib
->fib_DirEntryType
= ST_ROOT
;
3800 fib
->fib_EntryType
= ST_ROOT
;
3801 fib
->fib_NumBlocks
= 1;
3802 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3803 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3811 name
= ln
->ln_FullName
;
3812 name_len
= strlen(name
);
3814 for(i
= name_len
-1 ; i
>= 0 ; i
--)
3816 if(name
[i
] == SMB_PATH_SEPARATOR
)
3823 /* Just checking: will the name fit? */
3824 if(name_len
>= sizeof(fib
->fib_FileName
))
3826 error
= ERROR_INVALID_COMPONENT_NAME
;
3830 /* Translate the name of the file/directory from UTF-8
3831 * into AmigaOS ISO 8859-1 (ISO Latin 1) encoding?
3835 UBYTE decoded_name
[MAX_FILENAME_LEN
];
3836 int decoded_name_len
;
3838 /* Try to decode the file file, translating it into ISO 8859-1 format. */
3839 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,NULL
,0);
3841 /* Decoding error occured, or the decoded name would be longer than
3842 * buffer would allow?
3844 if(decoded_name_len
< 0 || decoded_name_len
>= MAX_FILENAME_LEN
)
3846 error
= ERROR_INVALID_COMPONENT_NAME
;
3850 /* Decode the name for real. */
3851 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,decoded_name
,sizeof(decoded_name
));
3853 /* Store the decoded name in the form expected
3854 * by dos.library (which will then translate it again).
3856 fib
->fib_FileName
[0] = decoded_name_len
;
3857 memcpy(&fib
->fib_FileName
[1],decoded_name
,decoded_name_len
);
3861 /* Store the file/directory name in the form expected
3864 ConvertCString(fib
->fib_FileName
,sizeof(fib
->fib_FileName
),name
,name_len
);
3866 /* If necessary, translate the name to Amiga format using a mapping table. */
3868 TranslateBName(fib
->fib_FileName
,M2A
);
3871 fib
->fib_DirEntryType
= st
.is_dir
? ST_USERDIR
: ST_FILE
;
3872 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
3873 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
3874 fib
->fib_Size
= st
.size
;
3875 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3876 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3879 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
3881 /* Careful: the 'archive' attribute has exactly the opposite
3882 * meaning in the Amiga and the SMB worlds.
3884 if(NOT st
.is_archive
)
3885 fib
->fib_Protection
|= FIBF_ARCHIVE
;
3888 fib
->fib_Protection
|= FIBF_PURE
;
3891 fib
->fib_DiskKey
= -1;
3897 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib
->fib_FileName
)));
3898 SHOWVALUE(fib
->fib_DirEntryType
);
3899 SHOWVALUE(fib
->fib_NumBlocks
);
3900 SHOWVALUE(fib
->fib_Size
);
3901 SHOWVALUE(fib
->fib_Date
.ds_Days
);
3902 SHOWVALUE(fib
->fib_Date
.ds_Minute
);
3903 SHOWVALUE(fib
->fib_Date
.ds_Tick
);
3904 SHOWVALUE(fib
->fib_DiskKey
);
3908 (*error_ptr
) = error
;
3914 /****************************************************************************/
3917 NameIsAcceptable(STRPTR name
,LONG max_len
)
3919 BOOL result
= FALSE
;
3922 /* This takes care of "." and "..". */
3923 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
3926 /* Now for embedded '/', ':' and '\' characters and
3927 * names that just don't want to fit.
3929 while((c
= (*name
++)) != '\0')
3932 if(max_len
== 0 || c
== '/' || c
== ':' || c
== SMB_PATH_SEPARATOR
)
3943 /****************************************************************************/
3946 dir_scan_callback_func_exnext(
3947 struct FileInfoBlock
* fib
,
3961 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
3962 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
3963 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
3965 /* Skip file and drawer names that we wouldn't be
3966 * able to handle in the first place.
3968 if(!NameIsAcceptable((STRPTR
)name
,sizeof(fib
->fib_FileName
)) || (st
->is_hidden
&& OmitHidden
))
3971 name_len
= strlen(name
);
3975 UBYTE decoded_name
[MAX_FILENAME_LEN
];
3976 int decoded_name_len
;
3978 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,NULL
,0);
3979 if(decoded_name_len
< 0 || decoded_name_len
>= MAX_FILENAME_LEN
)
3982 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,decoded_name
,sizeof(decoded_name
));
3984 fib
->fib_FileName
[0] = decoded_name_len
;
3985 memcpy(&fib
->fib_FileName
[1],decoded_name
,decoded_name_len
);
3989 ConvertCString(fib
->fib_FileName
,sizeof(fib
->fib_FileName
),name
,name_len
);
3992 TranslateBName(fib
->fib_FileName
,M2A
);
3995 fib
->fib_DirEntryType
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
3996 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
3997 fib
->fib_NumBlocks
= (st
->size
+ 511) / 512;
3998 fib
->fib_Size
= st
->size
;
3999 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
4000 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
4003 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4005 /* Careful: the 'archive' attribute has exactly the opposite
4006 * meaning in the Amiga and the SMB worlds.
4008 if(NOT st
->is_archive
)
4009 fib
->fib_Protection
|= FIBF_ARCHIVE
;
4012 fib
->fib_Protection
|= FIBF_PURE
;
4014 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4015 seconds
= (st
->mtime
== 0 ? st
->ctime
: st
->mtime
) - UNIX_TIME_OFFSET
- GetTimeZoneDelta();
4019 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
4020 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
4021 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
4027 fib
->fib_DiskKey
= eof
? -1 : nextpos
;
4035 struct FileLock
* lock
,
4036 struct FileInfoBlock
* fib
,
4039 struct LockNode
* ln
;
4040 LONG result
= DOSFALSE
;
4049 if(fib
->fib_DiskKey
== -1)
4051 SHOWMSG("scanning finished.");
4052 error
= ERROR_NO_MORE_ENTRIES
;
4058 SHOWMSG("invalid lock");
4059 error
= ERROR_INVALID_LOCK
;
4063 offset
= fib
->fib_DiskKey
;
4065 ln
= (struct LockNode
*)lock
->fl_Key
;
4067 /* Check if we should restart scanning the directory
4068 * contents. This is tricky at best and may produce
4069 * irritating results :(
4071 if(ln
->ln_RestartExamine
)
4075 ln
->ln_RestartExamine
= FALSE
;
4078 memset(fib
,0,sizeof(*fib
));
4080 SHOWMSG("calling 'smba_readdir'");
4083 count
= smba_readdir(ln
->ln_File
,offset
,fib
,(smba_callback_t
)dir_scan_callback_func_exnext
);
4087 if(count
== 0 || fib
->fib_FileName
[0] == '\0')
4089 SHOWMSG("nothing to be read");
4090 fib
->fib_DiskKey
= -1;
4092 error
= ERROR_NO_MORE_ENTRIES
;
4095 else if (count
== (-EIO
))
4097 SHOWMSG("ouch! directory read error");
4098 fib
->fib_DiskKey
= -1;
4100 error
= ERROR_NO_DEFAULT_DIR
;
4105 SHOWMSG("error whilst scanning");
4107 fib
->fib_DiskKey
= -1;
4109 error
= MapErrnoToIoErr(count
);
4117 (*error_ptr
) = error
;
4123 /****************************************************************************/
4127 struct ExAllData
* ec_Last
;
4128 struct ExAllData
* ec_Next
;
4131 struct ExAllControl
* ec_Control
;
4134 BOOL ec_FirstAttempt
;
4138 dir_scan_callback_func_exall(
4139 struct ExAllContext
* ec
,
4146 UBYTE decoded_name
[MAX_FILENAME_LEN
];
4147 BOOL ignore_this_entry
= FALSE
;
4153 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4154 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
4155 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
4157 /* If necessary, translate the name of the file first, so that we
4158 * can decide early on whether or not it should show up in a
4159 * directory listing. This filters out, for example, files using
4160 * characters which are not usable on the Amiga because they fall
4161 * outside the 8 bit character set used.
4165 LONG name_len
= strlen(name
);
4166 int decoded_name_len
;
4168 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,NULL
,0);
4169 if(decoded_name_len
< 0 || decoded_name_len
>= MAX_FILENAME_LEN
)
4171 ignore_this_entry
= TRUE
;
4175 decode_utf8_as_iso8859_1_string(name
,name_len
,decoded_name
,sizeof(decoded_name
));
4177 /* Use the decoded replacement name. */
4178 name
= decoded_name
;
4182 /* Skip file and drawer names that we wouldn't be
4183 * able to handle in the first place.
4185 if(!ignore_this_entry
&& NameIsAcceptable((STRPTR
)name
,MAX_FILENAME_LEN
) && NOT (st
->is_hidden
&& OmitHidden
))
4187 struct ExAllData
* ed
;
4189 ULONG type
= ec
->ec_Type
;
4192 size
= (ec
->ec_MinSize
+ strlen(name
)+1 + 3) & ~3UL;
4194 if(size
> ec
->ec_BytesLeft
)
4196 D(("size %ld > ec->ec_BytesLeft %ld",size
,ec
->ec_BytesLeft
));
4198 /* If this is the first directory entry,
4199 * stop the entire process before it has
4202 if(ec
->ec_FirstAttempt
)
4204 SHOWMSG("this was the first read attempt.");
4205 ec
->ec_Control
->eac_Entries
= 0;
4206 ec
->ec_Error
= ERROR_NO_FREE_STORE
;
4210 SHOWMSG("try again");
4221 ed
->ed_Name
= (STRPTR
)(((IPTR
)ed
) + ec
->ec_MinSize
);
4222 strcpy(ed
->ed_Name
,name
);
4224 if(!TranslateUTF8
&& TranslateNames
)
4225 TranslateCName(ed
->ed_Name
,M2A
);
4228 ed
->ed_Type
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
4231 ed
->ed_Size
= st
->size
;
4233 if(type
>= ED_PROTECTION
)
4235 ed
->ed_Prot
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
4236 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
4239 ed
->ed_Prot
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4241 /* Careful: the 'archive' attribute has exactly the opposite
4242 * meaning in the Amiga and the SMB worlds.
4244 if(NOT st
->is_archive
)
4245 ed
->ed_Prot
|= FIBF_ARCHIVE
;
4248 ed
->ed_Prot
|= FIBF_PURE
;
4255 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
4256 seconds
= (st
->mtime
== 0 ? st
->ctime
: st
->mtime
) - UNIX_TIME_OFFSET
- GetTimeZoneDelta();
4260 ed
->ed_Days
= (seconds
/ (24 * 60 * 60));
4261 ed
->ed_Mins
= (seconds
% (24 * 60 * 60)) / 60;
4262 ed
->ed_Ticks
= (seconds
% 60) * TICKS_PER_SECOND
;
4265 if(type
>= ED_COMMENT
)
4266 ed
->ed_Comment
= "";
4268 if(type
>= ED_OWNER
)
4269 ed
->ed_OwnerUID
= ed
->ed_OwnerGID
= 0;
4273 if(ec
->ec_Control
->eac_MatchString
!= NULL
)
4275 SHOWMSG("checking against match string");
4276 if(NOT
MatchPatternNoCase(ec
->ec_Control
->eac_MatchString
,ed
->ed_Name
))
4278 SHOWMSG("does not match");
4283 if(take_it
&& ec
->ec_Control
->eac_MatchFunc
!= NULL
)
4285 SHOWMSG("calling match func");
4287 /* NOTE: the order of the parameters passed to the match hook
4288 * function can be somewhat confusing. For standard
4289 * hook functions, the order of the parameters and the
4290 * registers they go into is hook=A0, object=A2,
4291 * message=A1. However, the documentation for the 'ExAll()'
4292 * function always lists them in ascending order, that is
4293 * hook=A0, message=A1, object=A2, which can lead to
4294 * quite some confusion and strange errors.
4296 if(NOT
CallHookPkt(ec
->ec_Control
->eac_MatchFunc
,&type
,ed
))
4298 SHOWMSG("does not match");
4305 SHOWMSG("registering new entry");
4307 if(ec
->ec_Last
!= NULL
)
4308 ec
->ec_Last
->ed_Next
= ed
;
4311 ec
->ec_Next
= (struct ExAllData
*)(((IPTR
)ed
) + size
);
4312 ec
->ec_BytesLeft
-= size
;
4313 ec
->ec_Control
->eac_Entries
++;
4315 SHOWVALUE(ec
->ec_Last
->ed_Next
);
4316 SHOWVALUE(ed
->ed_Name
);
4317 SHOWVALUE(ed
->ed_Comment
);
4321 ec
->ec_Control
->eac_LastKey
= (ULONG
)(eof
? -1 : nextpos
);
4325 ec
->ec_FirstAttempt
= FALSE
;
4333 struct FileLock
* lock
,
4334 struct ExAllData
* ed
,
4337 struct ExAllControl
* eac
,
4340 struct ExAllContext ec
;
4341 struct LockNode
* ln
;
4342 LONG result
= DOSFALSE
;
4351 SHOWVALUE(eac
->eac_LastKey
);
4353 eac
->eac_Entries
= 0;
4355 if(size
< sizeof(ed
->ed_Next
))
4357 SHOWMSG("buffer is far too short.");
4358 error
= ERROR_NO_FREE_STORE
;
4364 if(eac
->eac_LastKey
== (ULONG
)-1)
4366 SHOWMSG("scanning finished.");
4367 error
= ERROR_NO_MORE_ENTRIES
;
4373 SHOWMSG("invalid lock");
4374 error
= ERROR_INVALID_LOCK
;
4378 if(type
< ED_NAME
|| type
> ED_OWNER
)
4380 D(("type %ld not supported",type
));
4381 error
= ERROR_BAD_NUMBER
;
4387 memset(&ec
,0,sizeof(ec
));
4390 ec
.ec_BytesLeft
= size
;
4391 ec
.ec_Control
= eac
;
4393 ec
.ec_Error
= ERROR_NO_MORE_ENTRIES
;
4394 ec
.ec_FirstAttempt
= TRUE
;
4400 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Type
);
4405 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Size
);
4410 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Prot
);
4415 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Days
);
4420 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Comment
);
4425 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_OwnerUID
);
4430 ec
.ec_MinSize
= sizeof(struct ExAllData
);
4434 SHOWVALUE(ec
.ec_MinSize
);
4436 offset
= eac
->eac_LastKey
;
4438 ln
= (struct LockNode
*)lock
->fl_Key
;
4440 /* Check if we should restart scanning the directory
4441 * contents. This is tricky at best and may produce
4442 * irritating results :(
4444 if(ln
->ln_RestartExamine
)
4448 ln
->ln_RestartExamine
= FALSE
;
4455 SHOWMSG("first invocation");
4457 SHOWMSG("getting file attributes");
4458 error
= smba_getattr(ln
->ln_File
,&st
);
4461 SHOWMSG("didn't work");
4462 error
= MapErrnoToIoErr(error
);
4463 eac
->eac_LastKey
= (ULONG
)-1;
4469 SHOWMSG("lock does not refer to a directory");
4470 error
= ERROR_OBJECT_WRONG_TYPE
;
4471 eac
->eac_LastKey
= (ULONG
)-1;
4476 SHOWMSG("calling 'smba_readdir'");
4479 count
= smba_readdir(ln
->ln_File
,offset
,&ec
,(smba_callback_t
)dir_scan_callback_func_exall
);
4483 if(count
== 0 || eac
->eac_Entries
== 0)
4485 SHOWMSG("nothing to be read");
4486 if(ec
.ec_Error
!= OK
)
4488 SHOWMSG("flagging an error");
4489 SHOWVALUE(ec
.ec_Error
);
4490 eac
->eac_LastKey
= (ULONG
)-1;
4491 error
= ec
.ec_Error
;
4496 else if (count
== (-EIO
))
4498 SHOWMSG("ouch! directory read error");
4499 eac
->eac_LastKey
= (ULONG
)-1;
4501 error
= ERROR_NO_DEFAULT_DIR
;
4506 SHOWMSG("error whilst scanning");
4507 eac
->eac_LastKey
= (ULONG
)-1;
4509 error
= MapErrnoToIoErr(count
);
4520 SHOWVALUE(eac
->eac_Entries
);
4524 SHOWSTRING(ed
->ed_Name
);
4531 (*error_ptr
) = error
;
4537 /****************************************************************************/
4542 struct FileHandle
* fh
,
4543 struct FileLock
* parent
,
4547 LONG result
= DOSFALSE
;
4548 STRPTR parent_path
= NULL
;
4549 STRPTR full_name
= NULL
;
4550 LONG full_name_size
;
4551 struct FileNode
* fn
= NULL
;
4553 UBYTE name
[MAX_FILENAME_LEN
];
4554 BOOL create_new_file
;
4561 case ACTION_FINDINPUT
:
4562 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name
)));
4565 case ACTION_FINDOUTPUT
:
4566 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name
)));
4569 case ACTION_FINDUPDATE
:
4570 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name
)));
4578 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
4580 parent_name
= ln
->ln_FullName
;
4587 ConvertBString(sizeof(name
),name
,bcpl_name
);
4591 UBYTE encoded_name
[MAX_FILENAME_LEN
];
4592 int encoded_name_len
;
4593 LONG name_len
= strlen(name
);
4595 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
4596 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
4598 error
= ERROR_INVALID_COMPONENT_NAME
;
4602 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
4604 strlcpy(name
,encoded_name
,sizeof(name
));
4606 else if (TranslateNames
)
4608 TranslateCName(name
,A2M
);
4611 if(IsReservedName(FilePart(name
)))
4613 error
= ERROR_OBJECT_NOT_FOUND
;
4617 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
4621 /* Trying to open the root directory? */
4622 if(full_name
== NULL
)
4624 error
= ERROR_OBJECT_WRONG_TYPE
;
4628 fn
= AllocateMemory(sizeof(*fn
));
4631 error
= ERROR_NO_FREE_STORE
;
4635 memset(fn
,0,sizeof(*fn
));
4638 fn
->fn_FullName
= full_name
;
4639 fn
->fn_Mode
= (action
== ACTION_FINDOUTPUT
) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
4641 error
= CheckAccessModeCollision(full_name
,fn
->fn_Mode
);
4645 SHOWSTRING(full_name
);
4647 if(action
== ACTION_FINDOUTPUT
)
4649 /* Definitely create a new file. */
4650 create_new_file
= TRUE
;
4652 else if (action
== ACTION_FINDINPUT
)
4654 /* Open an existing file for reading. */
4655 create_new_file
= FALSE
;
4657 else if (action
== ACTION_FINDUPDATE
)
4659 smba_file_t
* file
= NULL
;
4662 if(smba_open(ServerData
,full_name
,full_name_size
,&file
) == OK
&&
4663 smba_getattr(file
,&st
) == OK
)
4665 /* File apparently opens Ok and information on it
4666 * is available, don't try to replace it.
4668 create_new_file
= FALSE
;
4672 /* We try to ignore the error here and assume
4673 * that the remainder of the file opening
4674 * procedure will produce a useful error
4675 * report. In the mean time, assume that the
4676 * file needs to be created.
4678 create_new_file
= TRUE
;
4687 error
= ERROR_ACTION_NOT_KNOWN
;
4691 /* Create a new file? */
4701 error
= ERROR_DISK_WRITE_PROTECTED
;
4705 parent_path
= AllocateMemory(strlen(full_name
)+3);
4706 if(parent_path
== NULL
)
4708 error
= ERROR_NO_FREE_STORE
;
4712 strcpy(parent_path
,full_name
);
4714 for(i
= strlen(parent_path
)-1 ; i
>= 0 ; i
--)
4716 if(parent_path
[i
] == SMB_PATH_SEPARATOR
)
4720 memmove(&parent_path
[1],&parent_path
[0],strlen(parent_path
)+1);
4724 parent_path
[i
] = '\0';
4726 base_name
= &parent_path
[i
+1];
4731 SHOWMSG("creating a file; finding parent path first");
4732 SHOWSTRING(parent_path
);
4734 error
= smba_open(ServerData
,parent_path
,strlen(full_name
)+3,&dir
);
4737 error
= MapErrnoToIoErr(error
);
4741 /* Only one attribute counts: the file should not be write protected. */
4742 memset(&st
,0,sizeof(st
));
4744 SHOWMSG("now trying to create the file");
4745 SHOWSTRING(base_name
);
4747 error
= smba_create(dir
,base_name
,&st
);
4750 SHOWMSG("didn't work.");
4754 error
= MapErrnoToIoErr(error
);
4766 /* Now for the remainder... */
4767 error
= smba_open(ServerData
,full_name
,full_name_size
,&fn
->fn_File
);
4770 error
= MapErrnoToIoErr(error
);
4774 fh
->fh_Arg1
= (IPTR
)fn
;
4776 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
4781 if(result
== DOSFALSE
)
4783 FreeMemory(full_name
);
4787 FreeMemory(parent_path
);
4789 (*error_ptr
) = error
;
4795 /****************************************************************************/
4799 struct FileNode
* fn
,
4811 result
= smba_read(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4814 error
= MapErrnoToIoErr(result
);
4819 fn
->fn_Offset
+= result
;
4824 (*error_ptr
) = error
;
4830 /****************************************************************************/
4834 struct FileNode
* fn
,
4839 LONG result
= DOSFALSE
;
4846 error
= ERROR_DISK_WRITE_PROTECTED
;
4852 result
= smba_write(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4855 error
= MapErrnoToIoErr(result
);
4860 fn
->fn_Offset
+= result
;
4865 (*error_ptr
) = error
;
4871 /****************************************************************************/
4875 struct FileNode
* fn
,
4878 Remove((struct Node
*)fn
);
4880 smba_close(fn
->fn_File
);
4881 FreeMemory(fn
->fn_FullName
);
4888 /****************************************************************************/
4892 struct FileNode
* fn
,
4897 LONG previous_position
= fn
->fn_Offset
;
4904 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4909 case OFFSET_BEGINNING
:
4914 case OFFSET_CURRENT
:
4926 error
= ERROR_ACTION_NOT_KNOWN
;
4930 error
= smba_seek (fn
->fn_File
, position
, mode
, (off_t
*) &offset
);
4933 error
= MapErrnoToIoErr(error
);
4939 /* olsen: This is the original implementation. */
4944 error
= smba_getattr(fn
->fn_File
,&st
);
4947 error
= MapErrnoToIoErr(error
);
4951 offset
= fn
->fn_Offset
;
4955 case OFFSET_BEGINNING
:
4960 case OFFSET_CURRENT
:
4967 offset
= st
.size
+ position
;
4972 error
= ERROR_ACTION_NOT_KNOWN
;
4976 if(offset
< 0 || offset
> st
.size
)
4978 error
= ERROR_SEEK_ERROR
;
4984 /* olsen: This is a mix of the two above. First we calculate the absolute
4985 * position, then seek to that position. The SMB server is supposed
4986 * to do its housekeeping before the position is changed. I wish this
4987 * worked differently, but it seems we've got the best of both worlds
4996 case OFFSET_BEGINNING
:
5001 case OFFSET_CURRENT
:
5003 offset
= fn
->fn_Offset
+ position
;
5008 error
= smba_getattr(fn
->fn_File
,&st
);
5011 error
= MapErrnoToIoErr(error
);
5015 offset
= st
.size
+ position
;
5020 error
= ERROR_ACTION_NOT_KNOWN
;
5026 error
= ERROR_SEEK_ERROR
;
5030 error
= smba_seek (fn
->fn_File
, offset
, 0, (off_t
*) &offset
);
5033 error
= MapErrnoToIoErr(error
);
5041 fn
->fn_Offset
= offset
;
5043 result
= previous_position
;
5047 (*error_ptr
) = error
;
5053 /****************************************************************************/
5057 struct FileNode
* fn
,
5071 error
= ERROR_DISK_WRITE_PROTECTED
;
5075 error
= smba_getattr(fn
->fn_File
,&st
);
5078 error
= MapErrnoToIoErr(error
);
5082 offset
= fn
->fn_Offset
;
5086 case OFFSET_BEGINNING
:
5091 case OFFSET_CURRENT
:
5098 offset
= st
.size
+ position
;
5103 error
= ERROR_ACTION_NOT_KNOWN
;
5109 error
= ERROR_SEEK_ERROR
;
5118 error
= smba_setattr(fn
->fn_File
,&st
);
5121 error
= MapErrnoToIoErr(error
);
5125 if(fn
->fn_Offset
> offset
)
5126 fn
->fn_Offset
= offset
;
5132 (*error_ptr
) = error
;
5138 /****************************************************************************/
5142 struct FileLock
* parent
,
5144 struct DateStamp
* ds
,
5147 LONG result
= DOSFALSE
;
5148 STRPTR full_name
= NULL
;
5149 LONG full_name_size
;
5150 smba_file_t
* file
= NULL
;
5152 UBYTE name
[MAX_FILENAME_LEN
];
5161 error
= ERROR_DISK_WRITE_PROTECTED
;
5169 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5171 parent_name
= ln
->ln_FullName
;
5178 ConvertBString(sizeof(name
),name
,bcpl_name
);
5182 UBYTE encoded_name
[MAX_FILENAME_LEN
];
5183 int encoded_name_len
;
5184 LONG name_len
= strlen(name
);
5186 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
5187 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
5189 error
= ERROR_INVALID_COMPONENT_NAME
;
5193 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
5195 strlcpy(name
,encoded_name
,sizeof(name
));
5197 else if (TranslateNames
)
5199 TranslateCName(name
,A2M
);
5202 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
5206 /* Trying to change the date of the root directory? */
5207 if(full_name
== NULL
)
5209 error
= ERROR_OBJECT_IN_USE
;
5213 SHOWSTRING(full_name
);
5215 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5218 error
= MapErrnoToIoErr(error
);
5222 error
= smba_getattr(file
,&st
);
5225 error
= MapErrnoToIoErr(error
);
5229 seconds
= (ds
->ds_Days
* 24 * 60 + ds
->ds_Minute
) * 60 + (ds
->ds_Tick
/ TICKS_PER_SECOND
);
5233 st
.mtime
= seconds
+ UNIX_TIME_OFFSET
+ GetTimeZoneDelta();
5236 error
= smba_setattr(file
,&st
);
5239 error
= MapErrnoToIoErr(error
);
5247 FreeMemory(full_name
);
5252 (*error_ptr
) = error
;
5258 /****************************************************************************/
5262 struct FileNode
* fn
,
5263 struct FileInfoBlock
* fib
,
5266 LONG result
= DOSFALSE
;
5276 error
= smba_getattr(fn
->fn_File
,&st
);
5279 error
= MapErrnoToIoErr(error
);
5283 name
= fn
->fn_FullName
;
5284 name_len
= strlen(name
);
5286 for(i
= name_len
; i
>= 0 ; i
--)
5288 if(name
[i
] == SMB_PATH_SEPARATOR
)
5295 /* Just checking: will the name fit? */
5296 if(name_len
>= sizeof(fib
->fib_FileName
))
5298 error
= ERROR_INVALID_COMPONENT_NAME
;
5302 memset(fib
,0,sizeof(*fib
));
5306 UBYTE decoded_name
[MAX_FILENAME_LEN
];
5307 int decoded_name_len
;
5309 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,NULL
,0);
5310 if(decoded_name_len
< 0 || decoded_name_len
>= MAX_FILENAME_LEN
)
5312 error
= ERROR_INVALID_COMPONENT_NAME
;
5316 decoded_name_len
= decode_utf8_as_iso8859_1_string(name
,name_len
,decoded_name
,sizeof(decoded_name
));
5318 fib
->fib_FileName
[0] = decoded_name_len
;
5319 memcpy(&fib
->fib_FileName
[1],decoded_name
,decoded_name_len
);
5323 ConvertCString(fib
->fib_FileName
,sizeof(fib
->fib_FileName
),name
,name_len
);
5326 TranslateBName(fib
->fib_FileName
,M2A
);
5329 fib
->fib_DirEntryType
= ST_FILE
;
5330 fib
->fib_EntryType
= ST_FILE
;
5331 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
5332 fib
->fib_Size
= st
.size
;
5333 fib
->fib_DiskKey
= -1;
5335 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
5336 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
5339 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
5341 /* Careful: the 'archive' attribute has exactly the opposite
5342 * meaning in the Amiga and the SMB worlds.
5344 if(NOT st
.is_archive
)
5345 fib
->fib_Protection
|= FIBF_ARCHIVE
;
5348 fib
->fib_Protection
|= FIBF_PURE
;
5350 /* If modification time is 0 use creation time instead (cyfm 2009-03-18). */
5351 seconds
= (st
.mtime
== 0 ? st
.ctime
: st
.mtime
) - UNIX_TIME_OFFSET
- GetTimeZoneDelta();
5355 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
5356 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
5357 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
5363 (*error_ptr
) = error
;
5369 /****************************************************************************/
5373 struct FileNode
* fn
,
5377 struct LockNode
* ln
= NULL
;
5380 LONG full_name_size
;
5385 full_name_size
= strlen(fn
->fn_FullName
)+3;
5386 if(full_name_size
< SMB_MAXNAMELEN
+1)
5387 full_name_size
= SMB_MAXNAMELEN
+1;
5389 full_name
= AllocateMemory(full_name_size
);
5390 if(full_name
== NULL
)
5392 error
= ERROR_NO_FREE_STORE
;
5396 strcpy(full_name
,fn
->fn_FullName
);
5398 for(i
= strlen(full_name
)-1 ; i
>= 0 ; i
--)
5402 strcpy(full_name
,SMB_ROOT_DIR_NAME
);
5405 else if (full_name
[i
] == SMB_PATH_SEPARATOR
)
5407 full_name
[i
] = '\0';
5412 ln
= AllocateMemory(sizeof(*ln
));
5415 error
= ERROR_NO_FREE_STORE
;
5419 memset(ln
,0,sizeof(*ln
));
5421 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
5422 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
5423 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
5424 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
5425 ln
->ln_FullName
= full_name
;
5427 SHOWSTRING(full_name
);
5429 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
5432 error
= MapErrnoToIoErr(error
);
5436 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5437 result
= MKBADDR(&ln
->ln_FileLock
);
5438 SHOWVALUE(&ln
->ln_FileLock
);
5445 FreeMemory(full_name
);
5448 (*error_ptr
) = error
;
5454 /****************************************************************************/
5458 struct FileNode
* fn
,
5462 struct LockNode
* ln
= NULL
;
5463 STRPTR full_name
= NULL
;
5464 LONG full_name_size
;
5469 if(fn
->fn_Mode
!= SHARED_LOCK
)
5471 error
= ERROR_OBJECT_IN_USE
;
5475 full_name_size
= strlen(fn
->fn_FullName
)+3;
5476 if(full_name_size
< SMB_MAXNAMELEN
+1)
5477 full_name_size
= SMB_MAXNAMELEN
+1;
5479 full_name
= AllocateMemory(full_name_size
);
5480 if(full_name
== NULL
)
5482 error
= ERROR_NO_FREE_STORE
;
5486 strcpy(full_name
,fn
->fn_FullName
);
5488 ln
= AllocateMemory(sizeof(*ln
));
5491 error
= ERROR_NO_FREE_STORE
;
5495 memset(ln
,0,sizeof(*ln
));
5497 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
5498 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
5499 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
5500 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
5501 ln
->ln_FullName
= full_name
;
5503 SHOWSTRING(full_name
);
5505 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
5508 error
= MapErrnoToIoErr(error
);
5512 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5513 result
= MKBADDR(&ln
->ln_FileLock
);
5514 SHOWVALUE(&ln
->ln_FileLock
);
5521 FreeMemory(full_name
);
5524 (*error_ptr
) = error
;
5530 /****************************************************************************/
5534 struct FileHandle
* fh
,
5535 struct FileLock
* fl
,
5538 LONG result
= DOSFALSE
;
5539 struct FileNode
* fn
;
5540 struct LockNode
* ln
;
5547 fn
= AllocateMemory(sizeof(*fn
));
5550 error
= ERROR_NO_FREE_STORE
;
5554 memset(fn
,0,sizeof(*fn
));
5556 ln
= (struct LockNode
*)fl
->fl_Key
;
5559 fn
->fn_FullName
= ln
->ln_FullName
;
5560 fn
->fn_File
= ln
->ln_File
;
5561 fn
->fn_Mode
= fl
->fl_Access
;
5563 Remove((struct Node
*)ln
);
5566 fh
->fh_Arg1
= (IPTR
)fn
;
5568 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
5573 (*error_ptr
) = error
;
5579 /****************************************************************************/
5586 LONG result
= DOSFALSE
;
5595 if(NOT VolumeNodeAdded
)
5597 error
= ERROR_OBJECT_IN_USE
;
5603 error
= ERROR_DISK_WRITE_PROTECTED
;
5607 /* Now for the really interesting part; the new name
5608 * is to be a NUL-terminated BCPL string, and as such
5609 * must be allocated via AllocVec().
5616 new_name
= AllocVec(1 + len
+ 1,MEMF_ANY
|MEMF_PUBLIC
);
5617 if(new_name
== NULL
)
5619 error
= ERROR_NO_FREE_STORE
;
5624 memcpy(&new_name
[1],&name
[1],len
);
5625 new_name
[len
+1] = '\0';
5629 old_name
= BADDR(VolumeNode
->dol_Name
);
5630 VolumeNode
->dol_Name
= MKBADDR(new_name
);
5636 SendDiskChange(IECLASS_DISKINSERTED
);
5642 (*error_ptr
) = error
;
5648 /****************************************************************************/
5657 LONG result
= DOSFALSE
;
5658 struct FileLock
* fl
= NULL
;
5659 struct FileNode
* fn
= NULL
;
5660 struct LockNode
* ln
= NULL
;
5667 /* Sanity check; verify parameters */
5668 if((type
!= CHANGE_LOCK
&& type
!= CHANGE_FH
) ||
5669 (new_mode
!= EXCLUSIVE_LOCK
&& new_mode
!= SHARED_LOCK
))
5671 error
= ERROR_ACTION_NOT_KNOWN
;
5675 /* Now obtain the data structures, name and mode
5676 * associated with the object in question.
5678 if(type
== CHANGE_LOCK
)
5681 ln
= (struct LockNode
*)fl
->fl_Key
;
5682 name
= ln
->ln_FullName
;
5683 old_mode
= fl
->fl_Access
;
5687 struct FileHandle
* fh
= object
;
5689 fn
= (struct FileNode
*)fh
->fh_Arg1
;
5690 name
= fn
->fn_FullName
;
5691 old_mode
= fn
->fn_Mode
;
5694 /* Do we need to change anything at all? */
5695 if(new_mode
== old_mode
)
5701 /* This is the easiest case; change an
5702 * exclusive access mode to a shared
5703 * access mode. Since the original mode
5704 * can be used by one object only,
5705 * we get away by updating the mode
5708 if(new_mode
== SHARED_LOCK
)
5710 if(type
== CHANGE_LOCK
)
5711 fl
->fl_Access
= new_mode
;
5713 fn
->fn_Mode
= new_mode
;
5719 /* Is there another shared access lock
5720 * which refers to the same object?
5722 if(FindLockNode(name
,ln
) != NULL
)
5724 error
= ERROR_OBJECT_IN_USE
;
5728 /* Is there another shared access file
5729 * which refers to the same object?
5731 if(FindFileNode(name
,fn
) != NULL
)
5733 error
= ERROR_OBJECT_IN_USE
;
5737 /* There is just one single reference
5738 * to this object; change the mode
5741 if(type
== CHANGE_LOCK
)
5742 fl
->fl_Access
= new_mode
;
5744 fn
->fn_Mode
= new_mode
;
5750 (*error_ptr
) = error
;
5756 /****************************************************************************/
5759 Action_WriteProtect(
5764 LONG result
= DOSFALSE
;
5769 if(flag
== DOSFALSE
)
5773 if(key
!= WriteProtectKey
)
5775 error
= ERROR_INVALID_LOCK
;
5779 WriteProtected
= FALSE
;
5783 SendDiskChange(IECLASS_DISKREMOVED
);
5784 SendDiskChange(IECLASS_DISKINSERTED
);
5790 if(NOT WriteProtected
)
5792 WriteProtected
= TRUE
;
5793 WriteProtectKey
= key
;
5797 SendDiskChange(IECLASS_DISKREMOVED
);
5798 SendDiskChange(IECLASS_DISKINSERTED
);
5803 error
= ERROR_INVALID_LOCK
;
5812 (*error_ptr
) = error
;
5818 /****************************************************************************/
5830 old_size
= smba_get_dircache_size(ServerData
);
5832 result
= smba_change_dircache_size(ServerData
,old_size
+ buffer_delta
);
5834 if(result
== old_size
&& buffer_delta
!= 0)
5837 (*error_ptr
) = ERROR_NO_FREE_STORE
;
5844 /****************************************************************************/
5848 struct FileLock
* parent
,
5853 LONG result
= DOSFALSE
;
5854 STRPTR full_name
= NULL
;
5855 LONG full_name_size
;
5856 smba_file_t
* file
= NULL
;
5858 UBYTE name
[MAX_FILENAME_LEN
];
5866 error
= ERROR_DISK_WRITE_PROTECTED
;
5874 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5876 parent_name
= ln
->ln_FullName
;
5883 ConvertBString(sizeof(name
),name
,bcpl_name
);
5887 UBYTE encoded_name
[MAX_FILENAME_LEN
];
5888 int encoded_name_len
;
5889 LONG name_len
= strlen(name
);
5891 encoded_name_len
= encode_iso8859_1_as_utf8_string(name
,name_len
,NULL
,0);
5892 if(encoded_name_len
< 0 || encoded_name_len
>= sizeof(name
))
5894 error
= ERROR_INVALID_COMPONENT_NAME
;
5898 encode_iso8859_1_as_utf8_string(name
,name_len
,encoded_name
,sizeof(encoded_name
));
5900 strlcpy(name
,encoded_name
,sizeof(name
));
5902 else if (TranslateNames
)
5904 TranslateCName(name
,A2M
);
5907 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
5911 /* Trying to change the comment of the root directory? */
5912 if(full_name
== NULL
)
5914 error
= ERROR_OBJECT_IN_USE
;
5918 SHOWSTRING(full_name
);
5920 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5923 error
= MapErrnoToIoErr(error
);
5927 ConvertBString(sizeof(comment
),comment
,bcpl_comment
);
5929 SHOWSTRING(comment
);
5931 /* All this work and we're only doing something very silly... */
5932 if(strlen(comment
) > 0)
5934 error
= ERROR_COMMENT_TOO_BIG
;
5942 FreeMemory(full_name
);
5947 (*error_ptr
) = error
;
5953 /****************************************************************************/
5957 struct FileNode
* fn
,
5964 LONG result
= DOSFALSE
;
5968 /* Sanity checks... */
5969 if (mode
< REC_EXCLUSIVE
|| mode
> REC_SHARED_IMMED
)
5971 error
= ERROR_ACTION_NOT_KNOWN
;
5975 /* Invalid offset, size or integer overflow? */
5976 if (offset
< 0 || length
<= 0 || offset
+ length
< offset
)
5978 error
= ERROR_LOCK_COLLISION
;
5982 if ((mode
== REC_SHARED
) || (mode
== REC_SHARED_IMMED
))
5987 if ((mode
== REC_SHARED_IMMED
) || (mode
== REC_EXCLUSIVE_IMMED
))
5992 if (timeout
> 214748364)
5993 timeout
= ~0; /* wait forever */
5995 timeout
*= 20; /* milliseconds instead of Ticks */
5998 error
= smba_lockrec (fn
->fn_File
, offset
, length
, umode
, 0, (long)timeout
);
6001 error
= MapErrnoToIoErr(error
);
6009 (*error_ptr
) = error
;
6015 /****************************************************************************/
6019 struct FileNode
* fn
,
6024 LONG result
= DOSFALSE
;
6027 /* Sanity checks... */
6028 if(offset
< 0 || length
<= 0 || offset
+ length
< offset
)
6030 error
= ERROR_RECORD_NOT_LOCKED
;
6034 error
= smba_lockrec (fn
->fn_File
, offset
, length
, 2, -1, 0);
6037 error
= MapErrnoToIoErr(error
);
6045 (*error_ptr
) = error
;
6051 /****************************************************************************/
6054 HandleFileSystem(VOID
)
6056 struct Process
* this_process
= (struct Process
*)FindTask(NULL
);
6057 BOOL sign_off
= FALSE
;
6069 /* Raise the Task priority of the file system to 10
6070 * unless it already is running at priority 10 or higher.
6074 old_priority
= this_process
->pr_Task
.tc_Node
.ln_Pri
;
6075 if(old_priority
< 10)
6076 SetTaskPri((struct Task
*)this_process
, 10);
6082 signals
= Wait(SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_F
| (1UL << FileSystemPort
->mp_SigBit
));
6084 if(signals
& (1UL << FileSystemPort
->mp_SigBit
))
6086 struct DosPacket
* dp
;
6087 struct Message
* mn
;
6090 while((mn
= GetMsg(FileSystemPort
)) != NULL
)
6092 dp
= (struct DosPacket
*)mn
->mn_Node
.ln_Name
;
6094 D(("got packet; sender '%s'",((struct Node
*)dp
->dp_Port
->mp_SigTask
)->ln_Name
));
6098 if (mn
->mn_Node
.ln_Type
== NT_REPLYMSG
)
6100 LONG max_transmit
= -1;
6101 if(args
.MaxTransmit
!= NULL
)
6102 max_transmit
= (*args
.MaxTransmit
);
6113 (args
.CacheSize
!= NULL
) ? *args
.CacheSize
: 0,
6115 !args
.NetBIOSTransport
/* Use raw SMB transport instead of NetBIOS transport? */
6119 if(!VolumeNodeAdded
&& dp
->dp_Action
!= ACTION_STARTUP
)
6122 res2
= ERROR_NO_DISK
;
6123 ReplyPkt(dp
,res1
,res2
);
6126 switch(dp
->dp_Action
)
6128 case ACTION_STARTUP
:
6129 /* FSSM,DeviceNode -> Bool */
6131 res1
= (IPTR
)Action_Startup(
6132 (struct FileSysStartupMsg
*)BADDR(dp
->dp_Arg2
),
6133 (struct DosList
*)BADDR(dp
->dp_Arg3
),&res2
);
6140 SHOWMSG("ACTION_DIE");
6141 if(IsListEmpty(&FileList
) && IsListEmpty(&LockList
))
6143 SHOWMSG("no locks or files pending; quitting");
6149 SHOWMSG("locks or files still pending; cannot quit yet");
6152 res2
= ERROR_OBJECT_IN_USE
;
6158 case ACTION_CURRENT_VOLUME
:
6159 /* (Ignore) -> VolumeNode */
6161 res1
= (IPTR
)MKBADDR(VolumeNode
);
6164 case ACTION_LOCATE_OBJECT
:
6165 /* Lock,Name,Mode -> Lock */
6167 res1
= (IPTR
)Action_LocateObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
6170 case ACTION_RENAME_DISK
:
6173 res1
= Action_RenameDisk((UBYTE
*)BADDR(dp
->dp_Arg1
),&res2
);
6176 case ACTION_FREE_LOCK
:
6179 res1
= Action_FreeLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6182 case ACTION_DELETE_OBJECT
:
6183 /* Lock,Name -> Bool */
6185 res1
= Action_DeleteObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
6188 case ACTION_RENAME_OBJECT
:
6189 /* Source lock,source name,destination lock,destination name -> Bool */
6191 res1
= Action_RenameObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),BADDR(dp
->dp_Arg2
),
6192 (struct FileLock
*)BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
6196 case ACTION_MORE_CACHE
:
6197 /* Buffer delta -> Total number of buffers */
6199 /* NOTE: documentation for this packet type is inconsistent;
6200 * in the 'good old' 1.x days 'res1' was documented as
6201 * the total number of buffers to be returned. In the
6202 * 2.x documentation it is said that 'res1' should
6203 * return the success code, with 'res2' to hold the
6204 * total number of buffers. However, the 'AddBuffers'
6205 * shell command doesn't work that way, and the
6206 * dos.library implementation of 'AddBuffers()' doesn't
6207 * work that way either. The 1.3 'AddBuffers' command
6208 * appears to treat a zero result as failure and a
6209 * non-zero result as success, which suggests that this
6210 * is how the packet is supposed to work, contrary to
6211 * what the official documentation says.
6213 res1
= Action_MoreCache(dp
->dp_Arg1
,&res2
);
6216 case ACTION_COPY_DIR
:
6219 res1
= (IPTR
)Action_CopyDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6222 case ACTION_SET_PROTECT
:
6223 /* (Ignore),Lock,Name,Mask -> Bool */
6225 res1
= Action_SetProtect((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),dp
->dp_Arg4
,&res2
);
6228 case ACTION_CREATE_DIR
:
6229 /* Lock,Name -> Lock */
6231 res1
= (IPTR
)Action_CreateDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
6234 case ACTION_EXAMINE_OBJECT
:
6235 /* FileLock,FileInfoBlock -> Bool */
6237 res1
= Action_ExamineObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6240 case ACTION_EXAMINE_NEXT
:
6241 /* FileLock,FileInfoBlock -> Bool */
6243 res1
= Action_ExamineNext((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6246 case ACTION_DISK_INFO
:
6247 /* InfoData -> Bool */
6249 Action_DiskInfo((struct InfoData
*)BADDR(dp
->dp_Arg1
),&res2
);
6255 /* FileLock,InfoData -> Bool */
6257 res1
= Action_Info((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct InfoData
*)BADDR(dp
->dp_Arg2
),&res2
);
6260 case ACTION_SET_COMMENT
:
6261 /* (Ignore),FileLock,Name,Comment -> Bool */
6263 res1
= Action_SetComment((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
6269 res1
= (IPTR
)Action_Parent((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6272 case ACTION_INHIBIT
:
6274 SHOWMSG("ACTION_INHIBIT");
6278 case ACTION_SET_DATE
:
6279 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
6281 res1
= Action_SetDate((struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),(struct DateStamp
*)dp
->dp_Arg4
,&res2
);
6284 case ACTION_SAME_LOCK
:
6285 /* Lock,Lock -> Bool */
6287 res1
= Action_SameLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
6291 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6293 res1
= Action_Read((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6297 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6299 res1
= Action_Write((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6302 case ACTION_FINDUPDATE
:
6303 case ACTION_FINDINPUT
:
6304 case ACTION_FINDOUTPUT
:
6305 /* FileHandle,FileLock,Name -> Bool */
6307 res1
= Action_Find(dp
->dp_Action
,(struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),&res2
);
6311 /* FileHandle->fh_Arg1 -> Bool */
6313 res1
= Action_End((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6317 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6319 res1
= Action_Seek((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6322 case ACTION_SET_FILE_SIZE
:
6323 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
6325 res1
= Action_SetFileSize((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6328 case ACTION_WRITE_PROTECT
:
6329 /* Flag,Key -> Bool */
6331 res1
= Action_WriteProtect(dp
->dp_Arg1
,dp
->dp_Arg2
,&res2
);
6334 case ACTION_FH_FROM_LOCK
:
6335 /* FileHandle(BPTR),FileLock -> Bool */
6337 res1
= Action_FHFromLock((struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
6340 case ACTION_IS_FILESYSTEM
:
6342 SHOWMSG("ACTION_IS_FILESYSTEM");
6346 case ACTION_CHANGE_MODE
:
6347 /* Type,Object,Mode -> Bool */
6349 res1
= Action_ChangeMode(dp
->dp_Arg1
,(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
6352 case ACTION_COPY_DIR_FH
:
6353 /* FileHandle->fh_Arg1 -> Bool */
6355 res1
= (IPTR
)Action_CopyDirFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6358 case ACTION_PARENT_FH
:
6359 /* FileHandle->fh_Arg1 -> Bool */
6361 res1
= (IPTR
)Action_ParentFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6364 case ACTION_EXAMINE_ALL
:
6365 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6367 res1
= Action_ExamineAll((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct ExAllData
*)dp
->dp_Arg2
,
6368 dp
->dp_Arg3
,dp
->dp_Arg4
,(struct ExAllControl
*)dp
->dp_Arg5
,&res2
);
6372 case ACTION_EXAMINE_FH
:
6373 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
6375 res1
= Action_ExamineFH((struct FileNode
*)dp
->dp_Arg1
,(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6378 case ACTION_EXAMINE_ALL_END
:
6379 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6384 case ACTION_LOCK_RECORD
:
6385 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
6386 res1
= Action_LockRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,dp
->dp_Arg4
,(ULONG
)dp
->dp_Arg5
,&res2
);
6389 case ACTION_FREE_RECORD
:
6390 /* FileHandle->fh_Arg1,position,length -> Bool */
6391 res1
= Action_FreeRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6396 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp
->dp_Action
,dp
->dp_Action
));
6398 /* Return -1 for ACTION_READ_LINK, for which DOSFALSE (= 0)
6399 * would otherwise be a valid response. Bug fix contributed
6400 * by Harry 'Piru' Sintonen.
6402 res1
= (dp
->dp_Action
== ACTION_READ_LINK
) ? -1 : DOSFALSE
;
6403 res2
= ERROR_ACTION_NOT_KNOWN
;
6411 ReplyPkt(dp
,res1
,res2
);
6419 if(signals
& SIGBREAKF_CTRL_F
)
6421 struct FileNode
* fn
;
6422 struct LockNode
* ln
;
6424 D(("list of open files:"));
6426 for(fn
= (struct FileNode
*)FileList
.mlh_Head
;
6427 fn
->fn_MinNode
.mln_Succ
!= NULL
;
6428 fn
= (struct FileNode
*)fn
->fn_MinNode
.mln_Succ
)
6430 D((" name='%s'",fn
->fn_FullName
));
6431 D((" mode=%ld, offset=%ld",fn
->fn_Mode
,fn
->fn_Offset
));
6435 D(("list of allocated locks:"));
6437 for(ln
= (struct LockNode
*)LockList
.mlh_Head
;
6438 ln
->ln_MinNode
.mln_Succ
!= NULL
;
6439 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
6441 D((" name='%s'",ln
->ln_FullName
));
6442 D((" mode=%ld",ln
->ln_FileLock
.fl_Access
));
6449 if(signals
& SIGBREAKF_CTRL_C
)
6454 if(IsListEmpty(&FileList
) && IsListEmpty(&LockList
))
6456 SHOWMSG("no locks or files pending; quitting");
6461 SHOWMSG("locks or files still pending; cannot quit yet");
6467 /* Restore the priority of the file system, unless the priority
6468 * has already been changed.
6472 if(old_priority
< 10 && this_process
->pr_Task
.tc_Node
.ln_Pri
== 10)
6473 SetTaskPri((struct Task
*)this_process
, old_priority
);
6478 LocalPrintf("stopped.\n");
6483 /****************************************************************************/
6486 * Copy src to string dst of size siz. At most siz-1 characters
6487 * will be copied. Always NUL terminates (unless siz == 0).
6488 * Returns strlen(src); if retval >= siz, truncation occurred.
6491 strlcpy(char *dst
, const char *src
, size_t siz
)
6494 const char *s
= src
;
6498 /* Copy as many bytes as will fit */
6499 if(n
!= 0 && --n
!= 0)
6503 if(((*d
++) = (*s
++)) == '\0')
6509 /* Not enough room in dst, add NUL and traverse rest of src */
6513 (*d
) = '\0'; /* NUL-terminate dst */
6515 while((*s
++) != '\0')
6519 result
= s
- src
- 1; /* count does not include NUL */
6525 * Appends src to string dst of size siz (unlike strncat, siz is the
6526 * full size of dst, not space left). At most siz-1 characters
6527 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
6528 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
6529 * If retval >= siz, truncation occurred.
6532 strlcat(char *dst
, const char *src
, size_t siz
)
6535 const char *s
= src
;
6540 /* Find the end of dst and adjust bytes left but don't go past end */
6541 while(n
-- != 0 && (*d
) != '\0')
6549 result
= dlen
+ strlen(s
);
6566 result
= dlen
+ (s
- src
); /* count does not include NUL */