6 * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
8 * Copyright (C) 2000-2009 by Olaf `Olsen' Barthel <obarthel -at- gmx -dot- net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 /****************************************************************************/
29 #include "smb_abstraction.h"
31 /****************************************************************************/
35 /****************************************************************************/
37 #if defined(__amigaos4__) && !defined(Flush)
38 #define Flush(fh) FFlush(fh)
39 #endif /* __amigaos4__ && !Flush */
41 /****************************************************************************/
43 /* A quick workaround for the timeval/timerequest->TimeVal/TimeRequest
44 change in the recent OS4 header files. */
45 #if defined(__NEW_TIMEVAL_DEFINITION_USED__)
47 #define timeval TimeVal
48 #define tv_secs Seconds
49 #define tv_micro Microseconds
51 #define timerequest TimeRequest
52 #define tr_node Request
55 #endif /* __NEW_TIMEVAL_DEFINITION_USED__ */
57 /****************************************************************************/
59 /* This is for backwards compatibility only. */
60 #if defined(__amigaos4__)
61 #define fib_EntryType fib_Obsolete
62 #endif /* __amigaos4__ */
64 /****************************************************************************/
66 #include "smbfs_rev.h"
67 STRPTR Version
= VERSTAG
;
69 /****************************************************************************/
71 #define UNIX_TIME_OFFSET 252460800
72 #define MAX_FILENAME_LEN 256
74 /****************************************************************************/
76 #define SMB_ROOT_DIR_NAME "\\"
77 #define SMB_PATH_SEPARATOR '\\'
79 /****************************************************************************/
82 typedef LONG
* NUMBER
;
85 /****************************************************************************/
89 struct MinNode fn_MinNode
;
90 struct FileHandle
* fn_Handle
;
93 smba_file_t
* fn_File
;
99 struct MinNode ln_MinNode
;
100 struct FileLock ln_FileLock
;
101 smba_file_t
* ln_File
;
102 BOOL ln_RestartExamine
;
107 /****************************************************************************/
109 /* The minimum operating system version we require to work. */
110 #define MINIMUM_OS_VERSION 37 /* Kickstart 2.04 or better */
111 /*#define MINIMUM_OS_VERSION 39*/ /* Kickstart 3.0 or better */
113 /****************************************************************************/
115 /* Careful: the memory pool routines in amiga.lib are available only to
116 * SAS/C and similar compilers (not necessarily to GCC).
118 #if defined(__GNUC__) && (MINIMUM_OS_VERSION < 39)
120 #undef MINIMUM_OS_VERSION
121 #define MINIMUM_OS_VERSION 39
123 #endif /* __GNUC__ */
125 /****************************************************************************/
127 #if (MINIMUM_OS_VERSION < 39)
129 /* These are in amiga.lib */
130 APTR ASM
AsmCreatePool(REG(d0
,ULONG memFlags
),REG(d1
,ULONG puddleSize
),REG(d2
,ULONG threshSize
),REG(a6
,struct Library
* SysBase
));
131 VOID ASM
AsmDeletePool(REG(a0
,APTR poolHeader
),REG(a6
,struct Library
* SysBase
));
132 APTR ASM
AsmAllocPooled(REG(a0
,APTR poolHeader
),REG(d0
,ULONG memSize
),REG(a6
,struct Library
* SysBase
));
133 VOID ASM
AsmFreePooled(REG(a0
,APTR poolHeader
),REG(a1
,APTR memory
),REG(d0
,ULONG memSize
),REG(a6
,struct Library
* SysBase
));
135 #define CreatePool(memFlags,puddleSize,threshSize) AsmCreatePool((memFlags),(puddleSize),(threshSize),SysBase)
136 #define DeletePool(poolHeader) AsmDeletePool((poolHeader),SysBase)
137 #define AllocPooled(poolHeader,memSize) AsmAllocPooled((poolHeader),(memSize),SysBase)
138 #define FreePooled(poolHeader,memory,memSize) AsmFreePooled((poolHeader),(memory),(memSize),SysBase)
140 #endif /* MINIMUM_OS_VERSION */
142 /****************************************************************************/
144 /* Forward declarations for local routines. */
145 #if !defined(__AROS__)
148 LONG VARARGS68K
LocalPrintf(STRPTR format
, ...);
149 STRPTR
amitcp_strerror(int error
);
150 STRPTR
host_strerror(int error
);
151 LONG
CompareNames(STRPTR a
, STRPTR b
);
152 VOID
StringToUpper(STRPTR s
);
154 VOID VARARGS68K
ReportError(STRPTR fmt
, ...);
156 VOID
FreeMemory(APTR address
);
157 APTR
AllocateMemory(ULONG size
);
158 LONG
GetTimeZoneDelta(VOID
);
159 ULONG
GetCurrentTime(VOID
);
160 VOID
GMTime(time_t seconds
, struct tm
*tm
);
161 time_t MakeTime(const struct tm
*const tm
);
163 VOID VARARGS68K
SPrintf(STRPTR buffer
, STRPTR formatString
, ...);
165 int BroadcastNameQuery(char *name
, char *scope
, UBYTE
*address
);
167 /****************************************************************************/
169 INLINE STATIC BOOL
ReallyRemoveDosEntry(struct DosList
*entry
);
170 INLINE STATIC LONG
BuildFullName(STRPTR parent_name
, STRPTR name
, STRPTR
*result_ptr
, LONG
*result_size_ptr
);
171 INLINE STATIC VOID
TranslateCName(UBYTE
*name
, UBYTE
*map
);
172 INLINE STATIC VOID
ConvertCString(LONG max_len
, APTR bstring
, STRPTR cstring
);
173 STATIC VOID
DisplayErrorList(VOID
);
174 STATIC VOID
AddError(STRPTR fmt
, APTR args
);
175 STATIC LONG
CVSPrintf(STRPTR format_string
, APTR args
);
176 STATIC VOID
VSPrintf(STRPTR buffer
, STRPTR formatString
, APTR args
);
177 STATIC VOID
SendDiskChange(ULONG
class);
178 STATIC
struct FileNode
*FindFileNode(STRPTR name
, struct FileNode
*skip
);
179 STATIC
struct LockNode
*FindLockNode(STRPTR name
, struct LockNode
*skip
);
180 STATIC LONG
CheckAccessModeCollision(STRPTR name
, LONG mode
);
181 STATIC LONG
NameAlreadyInUse(STRPTR name
);
182 STATIC BOOL
IsReservedName(STRPTR name
);
183 STATIC LONG
MapErrnoToIoErr(int error
);
184 STATIC VOID
TranslateBName(UBYTE
*name
, UBYTE
*map
);
185 STATIC VOID
Cleanup(VOID
);
186 STATIC BOOL
Setup(STRPTR program_name
, STRPTR service
, STRPTR workgroup
, STRPTR username
, STRPTR opt_password
, BOOL opt_changecase
, STRPTR opt_clientname
, STRPTR opt_servername
, int opt_cachesize
, LONG
*opt_time_zone_offset
, LONG
*opt_dst_offset
, STRPTR device_name
, STRPTR volume_name
, STRPTR translation_file
);
187 STATIC VOID
ConvertBString(LONG max_len
, STRPTR cstring
, APTR bstring
);
188 STATIC BPTR
Action_Parent(struct FileLock
*parent
, SIPTR
*error_ptr
);
189 STATIC LONG
Action_DeleteObject(struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
190 STATIC BPTR
Action_CreateDir(struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
191 STATIC BPTR
Action_LocateObject(struct FileLock
*parent
, APTR bcpl_name
, LONG mode
, SIPTR
*error_ptr
);
192 STATIC BPTR
Action_CopyDir(struct FileLock
*lock
, SIPTR
*error_ptr
);
193 STATIC LONG
Action_FreeLock(struct FileLock
*lock
, SIPTR
*error_ptr
);
194 STATIC LONG
Action_SameLock(struct FileLock
*lock1
, struct FileLock
*lock2
, SIPTR
*error_ptr
);
195 STATIC LONG
Action_SetProtect(struct FileLock
*parent
, APTR bcpl_name
, LONG mask
, SIPTR
*error_ptr
);
196 STATIC LONG
Action_RenameObject(struct FileLock
*source_lock
, APTR source_bcpl_name
, struct FileLock
*destination_lock
, APTR destination_bcpl_name
, SIPTR
*error_ptr
);
197 STATIC LONG
Action_DiskInfo(struct InfoData
*id
, SIPTR
*error_ptr
);
198 STATIC LONG
Action_Info(struct FileLock
*lock
, struct InfoData
*id
, SIPTR
*error_ptr
);
199 STATIC LONG
Action_ExamineObject(struct FileLock
*lock
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
200 STATIC BOOL
NameIsAcceptable(STRPTR name
, LONG max_len
);
201 STATIC LONG
Action_ExamineNext(struct FileLock
*lock
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
202 STATIC LONG
Action_ExamineAll(struct FileLock
*lock
, struct ExAllData
*ed
, ULONG size
, ULONG type
, struct ExAllControl
*eac
, SIPTR
*error_ptr
);
203 STATIC LONG
Action_Find(LONG action
, struct FileHandle
*fh
, struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
204 STATIC LONG
Action_Read(struct FileNode
*fn
, APTR mem
, LONG length
, SIPTR
*error_ptr
);
205 STATIC LONG
Action_Write(struct FileNode
*fn
, APTR mem
, LONG length
, SIPTR
*error_ptr
);
206 STATIC LONG
Action_End(struct FileNode
*fn
, SIPTR
*error_ptr
);
207 STATIC LONG
Action_Seek(struct FileNode
*fn
, LONG position
, LONG mode
, SIPTR
*error_ptr
);
208 STATIC LONG
Action_SetFileSize(struct FileNode
*fn
, LONG position
, LONG mode
, SIPTR
*error_ptr
);
209 STATIC LONG
Action_SetDate(struct FileLock
*parent
, APTR bcpl_name
, struct DateStamp
*ds
, SIPTR
*error_ptr
);
210 STATIC LONG
Action_ExamineFH(struct FileNode
*fn
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
211 STATIC BPTR
Action_ParentFH(struct FileNode
*fn
, SIPTR
*error_ptr
);
212 STATIC BPTR
Action_CopyDirFH(struct FileNode
*fn
, SIPTR
*error_ptr
);
213 STATIC LONG
Action_FHFromLock(struct FileHandle
*fh
, struct FileLock
*fl
, SIPTR
*error_ptr
);
214 STATIC LONG
Action_RenameDisk(APTR bcpl_name
, SIPTR
*error_ptr
);
215 STATIC LONG
Action_ChangeMode(LONG type
, APTR object
, LONG new_mode
, SIPTR
*error_ptr
);
216 STATIC LONG
Action_WriteProtect(LONG flag
, ULONG key
, SIPTR
*error_ptr
);
217 STATIC LONG
Action_MoreCache(LONG buffer_delta
, SIPTR
*error_ptr
);
218 STATIC LONG
Action_SetComment(struct FileLock
*parent
, APTR bcpl_name
, APTR bcpl_comment
, SIPTR
*error_ptr
);
219 STATIC LONG
Action_LockRecord(struct FileNode
*fn
, LONG offset
, LONG length
, LONG mode
, ULONG timeout
, SIPTR
*error_ptr
);
220 STATIC LONG
Action_FreeRecord(struct FileNode
*fn
, LONG offset
, LONG length
, SIPTR
*error_ptr
);
221 STATIC VOID
HandleFileSystem(STRPTR device_name
, STRPTR volume_name
, STRPTR service_name
);
223 /****************************************************************************/
225 #if !defined(__AROS__)
226 struct Library
* SysBase
;
228 struct Library
* DOSBase
;
229 struct Library
* UtilityBase
;
230 struct Library
* IntuitionBase
;
231 struct Library
* SocketBase
;
232 struct Library
* LocaleBase
;
233 struct Library
* TimerBase
;
234 struct Library
* IconBase
;
236 /****************************************************************************/
238 #if defined(__amigaos4__)
240 /****************************************************************************/
242 struct ExecIFace
* IExec
;
243 struct DOSIFace
* IDOS
;
244 struct UtilityIFace
* IUtility
;
245 struct IntuitionIFace
* IIntuition
;
246 struct SocketIFace
* ISocket
;
247 struct LocaleIFace
* ILocale
;
248 struct TimerIFace
* ITimer
;
249 struct IconIFace
* IIcon
;
251 /****************************************************************************/
253 #endif /* __amigaos4__ */
255 /****************************************************************************/
257 struct timerequest TimerRequest
;
259 /****************************************************************************/
261 struct Locale
* Locale
;
263 /****************************************************************************/
269 /****************************************************************************/
271 STATIC
struct DosList
* DeviceNode
;
272 STATIC BOOL DeviceNodeAdded
;
273 STATIC
struct DosList
* VolumeNode
;
274 STATIC BOOL VolumeNodeAdded
;
275 STATIC
struct MsgPort
* FileSystemPort
;
277 STATIC smba_server_t
* ServerData
;
281 STATIC BOOL CaseSensitive
;
282 STATIC BOOL OmitHidden
;
284 STATIC LONG DSTOffset
;
285 STATIC LONG TimeZoneOffset
;
286 STATIC BOOL OverrideLocaleTimeZone
;
288 STATIC BOOL WriteProtected
;
289 STATIC ULONG WriteProtectKey
;
291 STATIC
struct MinList FileList
;
292 STATIC
struct MinList LockList
;
294 STATIC APTR MemoryPool
;
296 STATIC
struct RDArgs
* Parameters
;
297 STATIC
struct DiskObject
* Icon
;
299 STATIC
struct WBStartup
* WBStartup
;
301 STATIC
struct MinList ErrorList
;
303 STATIC STRPTR NewProgramName
;
305 STATIC BOOL TranslateNames
;
306 STATIC UBYTE A2M
[256];
307 STATIC UBYTE M2A
[256];
309 /****************************************************************************/
311 #if !defined(__AROS__)
323 SWITCH CaseSensitive
;
332 NUMBER TimeZoneOffset
;
338 STRPTR cmd_template
=
339 "DOMAIN=WORKGROUP/K,"
343 "CASE=CASESENSITIVE/S,"
346 "CLIENT=CLIENTNAME/K,"
347 "SERVER=SERVERNAME/K,"
348 "DEVICE=DEVICENAME/K,"
349 "VOLUME=VOLUMENAME/K,"
350 "CACHE=CACHESIZE/N/K,"
351 "DEBUGLEVEL=DEBUG/N/K,"
352 "TZ=TIMEZONEOFFSET/N/K,"
354 "TRANSLATE=TRANSLATIONFILE/K,"
357 struct Process
* this_process
;
358 UBYTE program_name
[MAX_FILENAME_LEN
];
359 LONG result
= RETURN_FAIL
;
363 char env_workgroup_name
[17];
364 char env_user_name
[64];
365 char env_password
[64];
367 #if !defined(__AROS__)
368 SysBase
= (struct Library
*)AbsExecBase
;
370 #if defined(__amigaos4__)
372 IExec
= (struct ExecIFace
*)((struct ExecBase
*)SysBase
)->MainInterface
;
374 #endif /* __amigaos4__ */
376 /* Pick up the Workbench startup message, if
379 this_process
= (struct Process
*)FindTask(NULL
);
380 if(this_process
->pr_CLI
== ZERO
)
382 WaitPort(&this_process
->pr_MsgPort
);
383 WBStartup
= (struct WBStartup
*)GetMsg(&this_process
->pr_MsgPort
);
390 /* Don't emit any debugging output before we are ready. */
393 /* Open the libraries we need and check
394 * whether we could get them.
396 DOSBase
= OpenLibrary("dos.library",0);
398 #if defined(__amigaos4__)
402 IDOS
= (struct DOSIFace
*)GetInterface(DOSBase
, "main", 1, 0);
405 CloseLibrary(DOSBase
);
410 #endif /* __amigaos4__ */
412 UtilityBase
= OpenLibrary("utility.library",37);
414 #if defined(__amigaos4__)
416 if(UtilityBase
!= NULL
)
418 IUtility
= (struct UtilityIFace
*)GetInterface(UtilityBase
, "main", 1, 0);
421 CloseLibrary(UtilityBase
);
426 #endif /* __amigaos4__ */
428 if(UtilityBase
== NULL
|| DOSBase
== NULL
|| DOSBase
->lib_Version
< MINIMUM_OS_VERSION
)
430 /* Complain loudly if this is not the operating
431 * system version we expected.
433 if(DOSBase
!= NULL
&& this_process
->pr_CLI
!= ZERO
)
437 #if (MINIMUM_OS_VERSION < 39)
439 msg
= "AmigaOS 2.04 or higher required.\n";
443 msg
= "AmigaOS 3.0 or higher required.\n";
445 #endif /* MINIMUM_OS_VERSION */
447 Write(Output(),msg
,strlen(msg
));
453 /* This needs to be set up properly for ReportError()
456 NewList((struct List
*)&ErrorList
);
458 memset(&args
,0,sizeof(args
));
460 /* If this program was launched from Workbench,
461 * parameter passing will have to be handled
464 if(WBStartup
!= NULL
)
470 if(WBStartup
->sm_NumArgs
> 1)
475 /* Get the name of the program, as it was launched
476 * from Workbench. We actually prefer the name of
477 * the first project file, if there is one.
479 strlcpy(program_name
,WBStartup
->sm_ArgList
[n
].wa_Name
,sizeof(program_name
));
481 /* Now open icon.library and read that icon. */
482 IconBase
= OpenLibrary("icon.library",0);
484 #if defined(__amigaos4__)
488 IIcon
= (struct IconIFace
*)GetInterface(IconBase
, "main", 1, 0);
491 CloseLibrary(IconBase
);
496 #endif /* __amigaos4__ */
500 ReportError("Could not open 'icon.library'.");
504 old_dir
= CurrentDir(WBStartup
->sm_ArgList
[n
].wa_Lock
);
505 Icon
= GetDiskObject(WBStartup
->sm_ArgList
[n
].wa_Name
);
510 ReportError("Icon not found.");
514 /* Only input validation errors are reported below. */
515 result
= RETURN_ERROR
;
517 /* Examine the icon's tool types and use the
518 * information to fill the startup parameter
521 str
= FindToolType(Icon
->do_ToolTypes
,"DOMAIN");
523 str
= FindToolType(Icon
->do_ToolTypes
,"WORKGROUP");
527 if(GetVar("smbfs_domain",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0 ||
528 GetVar("smbfs_workgroup",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0)
530 str
= env_workgroup_name
;
534 ReportError("Required 'WORKGROUP' parameter was not provided.");
539 args
.Workgroup
= str
;
541 str
= FindToolType(Icon
->do_ToolTypes
,"USER");
543 str
= FindToolType(Icon
->do_ToolTypes
,"USERNAME");
547 if(GetVar("smbfs_user",env_user_name
,sizeof(env_user_name
),0) > 0 ||
548 GetVar("smbfs_username",env_user_name
,sizeof(env_user_name
),0) > 0)
556 str
= FindToolType(Icon
->do_ToolTypes
,"PASSWORD");
559 if(GetVar("smbfs_password",env_password
,sizeof(env_password
),0) > 0)
565 if(FindToolType(Icon
->do_ToolTypes
,"CHANGECASE") != NULL
)
566 args
.ChangeCase
= TRUE
;
568 if(FindToolType(Icon
->do_ToolTypes
,"OMITHIDDEN") != NULL
)
569 args
.OmitHidden
= TRUE
;
571 if(FindToolType(Icon
->do_ToolTypes
,"QUIET") != NULL
)
574 if(FindToolType(Icon
->do_ToolTypes
,"CASE") != NULL
||
575 FindToolType(Icon
->do_ToolTypes
,"CASESENSITIVE") != NULL
)
577 args
.CaseSensitive
= TRUE
;
580 str
= FindToolType(Icon
->do_ToolTypes
,"CLIENT");
582 str
= FindToolType(Icon
->do_ToolTypes
,"CLIENTNAME");
584 args
.ClientName
= str
;
586 str
= FindToolType(Icon
->do_ToolTypes
,"SERVER");
588 str
= FindToolType(Icon
->do_ToolTypes
,"SERVERNAME");
590 args
.ServerName
= str
;
592 str
= FindToolType(Icon
->do_ToolTypes
,"DEVICE");
594 str
= FindToolType(Icon
->do_ToolTypes
,"DEVICENAME");
596 args
.DeviceName
= str
;
598 str
= FindToolType(Icon
->do_ToolTypes
,"VOLUME");
600 str
= FindToolType(Icon
->do_ToolTypes
,"VOLUMENAME");
602 args
.VolumeName
= str
;
604 str
= FindToolType(Icon
->do_ToolTypes
,"TRANSLATE");
606 str
= FindToolType(Icon
->do_ToolTypes
,"TRANSLATIONFILE");
608 args
.TranslationFile
= str
;
610 str
= FindToolType(Icon
->do_ToolTypes
,"SERVICE");
615 /* Set up the name of the program, as it will be
616 * displayed in error requesters.
618 NewProgramName
= AllocVec(strlen(WBStartup
->sm_ArgList
[0].wa_Name
) + strlen(" ''") + strlen(str
)+1,MEMF_ANY
|MEMF_PUBLIC
);
619 if(NewProgramName
!= NULL
)
620 SPrintf(NewProgramName
,"%s '%s'",WBStartup
->sm_ArgList
[0].wa_Name
,str
);
623 str
= FindToolType(Icon
->do_ToolTypes
,"DEBUG");
625 str
= FindToolType(Icon
->do_ToolTypes
,"DEBUGLEVEL");
629 if(StrToLong(str
,&number
) == -1)
631 ReportError("Invalid number '%s'Â for 'DEBUG' parameter.",str
);
635 args
.DebugLevel
= &number
;
638 str
= FindToolType(Icon
->do_ToolTypes
,"TZ");
640 str
= FindToolType(Icon
->do_ToolTypes
,"TIMEZONEOFFSET");
644 if(StrToLong(str
,&other_number
) == -1)
646 ReportError("Invalid number '%s'Â for 'TIMEZONEOFFSET' parameter.",str
);
650 args
.TimeZoneOffset
= &other_number
;
653 str
= FindToolType(Icon
->do_ToolTypes
,"DST");
655 str
= FindToolType(Icon
->do_ToolTypes
,"DSTOFFSET");
659 if(StrToLong(str
,&other_number
) == -1)
661 ReportError("Invalid number '%s'Â for 'DSTOFFSET' parameter.",str
);
665 args
.DSTOffset
= &other_number
;
668 str
= FindToolType(Icon
->do_ToolTypes
,"CACHE");
670 str
= FindToolType(Icon
->do_ToolTypes
,"CACHESIZE");
674 if(StrToLong(str
,&number
) == -1)
676 ReportError("Invalid number '%s'Â for 'CACHE' parameter.",str
);
683 if(args
.Workgroup
== NULL
)
685 ReportError("Required 'WORKGROUP' parameter was not provided.");
689 if(args
.Service
== NULL
)
691 ReportError("'SERVICE' parameter needs an argument.");
697 /* Only input validation errors are reported below. */
698 result
= RETURN_ERROR
;
700 GetProgramName(program_name
,sizeof(program_name
));
702 Parameters
= ReadArgs(cmd_template
,(IPTR
*)&args
,NULL
);
703 if(Parameters
== NULL
)
705 PrintFault(IoErr(),FilePart(program_name
));
709 if(args
.Workgroup
== NULL
)
711 if(GetVar("smbfs_domain",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0 ||
712 GetVar("smbfs_workgroup",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0)
714 args
.Workgroup
= env_workgroup_name
;
718 ReportError("Required 'WORKGROUP' parameter was not provided.");
723 if(args
.UserName
== NULL
)
725 if(GetVar("smbfs_user",env_user_name
,sizeof(env_user_name
),0) > 0 ||
726 GetVar("smbfs_username",env_user_name
,sizeof(env_user_name
),0) > 0)
728 args
.UserName
= env_user_name
;
732 if(args
.Password
== NULL
)
734 if(GetVar("smbfs_password",env_password
,sizeof(env_password
),0) > 0)
735 args
.Password
= env_password
;
738 if(args
.Service
!= NULL
)
740 STRPTR name
= FilePart(program_name
);
742 /* Set up the name of the program, as it will be
743 * displayed in the proces status list.
745 NewProgramName
= AllocVec(strlen(name
) + strlen(" ''") + strlen(args
.Service
)+1,MEMF_ANY
|MEMF_PUBLIC
);
746 if(NewProgramName
!= NULL
)
747 SPrintf(NewProgramName
,"%s '%s'",name
,args
.Service
);
750 if(args
.CacheSize
!= NULL
)
751 cache_size
= (*args
.CacheSize
);
754 /* Use the default if no user name is given. */
755 if(args
.UserName
== NULL
)
756 args
.UserName
= "GUEST";
758 /* Use the default if no device or volume name is given. */
759 if(args
.DeviceName
== NULL
&& args
.VolumeName
== NULL
)
760 args
.DeviceName
= "SMBFS";
762 CaseSensitive
= (BOOL
)args
.CaseSensitive
;
763 OmitHidden
= (BOOL
)args
.OmitHidden
;
765 /* Configure the debugging options. */
766 SETPROGRAMNAME(FilePart(program_name
));
768 if(args
.DebugLevel
!= NULL
)
769 SETDEBUGLEVEL(*args
.DebugLevel
);
773 D(("%s (%s)",VERS
,DATE
));
776 FilePart(program_name
),
789 args
.TranslationFile
))
794 SHOWVALUE(Locale
->loc_GMTOffset
);
796 HandleFileSystem(args
.DeviceName
,args
.VolumeName
,args
.Service
);
798 result
= RETURN_WARN
;
802 result
= RETURN_ERROR
;
812 /****************************************************************************/
815 #define LocalPrintf(format,args...) Printf(format ,##args )
818 LocalPrintf(STRPTR format
, ...)
823 #if defined(__amigaos4__)
825 va_startlinear(args
,format
);
826 result
= VPrintf(format
,va_getlinearva(args
,APTR
));
831 va_start(args
,format
);
832 result
= VPrintf(format
,args
);
835 #endif /* __amigaos4__ */
839 #endif /* __AROS__ */
841 /****************************************************************************/
843 /* Obtain the descriptive text corresponding to an error number
844 * that may have been generated by the TCP/IP stack.
847 amitcp_strerror(int error
)
849 struct TagItem tags
[2];
854 tags
[0].ti_Tag
= SBTM_GETVAL(SBTC_ERRNOSTRPTR
);
855 tags
[0].ti_Data
= error
;
856 tags
[1].ti_Tag
= TAG_END
;
858 SocketBaseTagList(tags
);
860 result
= (STRPTR
)tags
[0].ti_Data
;
866 /****************************************************************************/
868 /* Return the descriptive text associated with a host lookup failure code. */
870 host_strerror(int error
)
872 struct TagItem tags
[2];
877 tags
[0].ti_Tag
= SBTM_GETVAL(SBTC_HERRNOSTRPTR
);
878 tags
[0].ti_Data
= error
;
879 tags
[1].ti_Tag
= TAG_END
;
881 SocketBaseTagList(tags
);
883 result
= (STRPTR
)tags
[0].ti_Data
;
889 /****************************************************************************/
891 /* Compare two strings, either case sensitive or not
892 * sensitive to the case of the letters. How this is
893 * to be done is controlled by a global option. This
894 * routine is called whenever two SMB file names are
898 CompareNames(STRPTR a
,STRPTR b
)
903 result
= strcmp(a
,b
);
905 result
= Stricmp(a
,b
);
910 /****************************************************************************/
912 /* Translate a string into all upper case characters. */
914 StringToUpper(STRPTR s
)
918 while((c
= (*s
)) != '\0')
922 /****************************************************************************/
924 /* Prepare the accumulated list of error messages for display
925 * and purge the contents of that list.
928 DisplayErrorList(VOID
)
930 struct MinNode
* last
= NULL
;
936 /* Determine how much memory will have to be
937 * allocated to hold all the accumulated
942 for(mn
= ErrorList
.mlh_Head
;
943 mn
->mln_Succ
!= NULL
;
948 msg
= (STRPTR
)(mn
+ 1);
950 len
+= strlen(msg
)+1;
953 /* Allocate the memory for the messages, then
958 str
= AllocVec(len
,MEMF_ANY
);
963 for(mn
= ErrorList
.mlh_Head
;
964 mn
->mln_Succ
!= NULL
;
967 msg
= (STRPTR
)(mn
+ 1);
976 /* Purge the list. */
977 while((mn
= (struct MinNode
*)RemHead((struct List
*)&ErrorList
)) != NULL
)
980 /* Display the error messages. */
983 IntuitionBase
= OpenLibrary("intuition.library",37);
985 #if defined(__amigaos4__)
987 if(IntuitionBase
!= NULL
)
989 IIntuition
= (struct IntuitionIFace
*)GetInterface(IntuitionBase
, "main", 1, 0);
990 if(IIntuition
== NULL
)
992 CloseLibrary(IntuitionBase
);
993 IntuitionBase
= NULL
;
997 #endif /* __amigaos4__ */
999 if(IntuitionBase
!= NULL
)
1001 struct EasyStruct es
;
1004 memset(&es
,0,sizeof(es
));
1006 if(NewProgramName
== NULL
)
1007 title
= WBStartup
->sm_ArgList
[0].wa_Name
;
1009 title
= NewProgramName
;
1011 es
.es_StructSize
= sizeof(es
);
1012 es
.es_Title
= title
;
1013 es
.es_TextFormat
= str
;
1014 es
.es_GadgetFormat
= "Ok";
1016 EasyRequestArgs(NULL
,&es
,NULL
,NULL
);
1022 #if defined(__amigaos4__)
1024 if(IIntuition
!= NULL
)
1026 DropInterface((struct Interface
*)IIntuition
);
1030 #endif /* __amigaos4__ */
1032 CloseLibrary(IntuitionBase
);
1033 IntuitionBase
= NULL
;
1036 /* Add another error message to the list; the messages are
1037 * collected so that they may be displayed together when
1041 AddError(STRPTR fmt
,APTR args
)
1045 len
= CVSPrintf(fmt
,args
);
1048 struct MinNode
* mn
;
1050 mn
= AllocVec(sizeof(*mn
) + len
,MEMF_ANY
|MEMF_PUBLIC
);
1053 STRPTR msg
= (STRPTR
)(mn
+ 1);
1055 VSPrintf(msg
,fmt
,args
);
1057 AddTail((struct List
*)&ErrorList
,(struct Node
*)mn
);
1062 /****************************************************************************/
1064 /* Report an error that has occured; if the program was not launched
1065 * from Shell, error messages will be accumulated for later display.
1068 VOID
VReportError(STRPTR fmt
, IPTR
*args
)
1072 if(WBStartup
!= NULL
)
1078 UBYTE program_name
[MAX_FILENAME_LEN
];
1080 GetProgramName(program_name
,sizeof(program_name
));
1082 LocalPrintf("%s: ",FilePart(program_name
));
1092 ReportError(STRPTR fmt
,...)
1098 if(WBStartup
!= NULL
)
1100 #if defined(__amigaos4__)
1102 va_startlinear(args
,fmt
);
1103 AddError(fmt
,va_getlinearva(args
,APTR
));
1112 #endif /* __amigaos4__ */
1116 UBYTE program_name
[MAX_FILENAME_LEN
];
1118 GetProgramName(program_name
,sizeof(program_name
));
1120 LocalPrintf("%s: ",FilePart(program_name
));
1122 #if defined(__amigaos4__)
1124 va_startlinear(args
,fmt
);
1125 VPrintf(fmt
,va_getlinearva(args
,APTR
));
1134 #endif /* __amigaos4__ */
1142 /****************************************************************************/
1144 /* Release memory allocated from the global pool. */
1146 FreeMemory(APTR address
)
1150 ULONG
* mem
= address
;
1154 if(GETDEBUGLEVEL() > 0)
1155 memset(address
,0xA3,mem
[-1] - sizeof(*mem
));
1159 FreePooled(MemoryPool
,&mem
[-1],mem
[-1]);
1163 /* Allocate memory from the global pool. */
1165 AllocateMemory(ULONG size
)
1173 size
= (sizeof(*mem
) + size
+ 7) & ~7UL;
1175 mem
= AllocPooled(MemoryPool
,size
);
1182 if(GETDEBUGLEVEL() > 0)
1183 memset(mem
,0xA5,mem
[-1] - sizeof(*mem
));
1194 /****************************************************************************/
1196 /* Obtain the number of seconds to add to the current time
1197 * to translate local time into UTC.
1200 GetTimeZoneDelta(VOID
)
1204 if(OverrideLocaleTimeZone
)
1206 seconds
= 60 * TimeZoneOffset
;
1208 else if (Locale
!= NULL
)
1210 /* The GMT offset actually is the number of minutes to add to
1211 * the local time to yield Greenwich Mean Time. It is negative
1212 * for all time zones east of the Greenwich meridian and
1213 * positive for all time zones west of it.
1215 seconds
= 60 * Locale
->loc_GMTOffset
;
1222 return(seconds
+ DSTOffset
);
1225 /****************************************************************************/
1227 /* Obtain the current time, in standard Unix format, adjusted for the
1231 GetCurrentTime(VOID
)
1236 GetSysTime((APTR
)&tv
);
1238 result
= UNIX_TIME_OFFSET
+ GetTimeZoneDelta() + tv
.tv_secs
;
1243 /****************************************************************************/
1245 /* Fill in a 'tm' type time specification with time information
1246 * corresponding to the number of seconds provided. Input is
1250 GMTime(time_t seconds
,struct tm
* tm
)
1252 struct ClockData clock_data
;
1254 if(seconds
< UNIX_TIME_OFFSET
)
1257 seconds
-= UNIX_TIME_OFFSET
;
1259 Amiga2Date(seconds
,&clock_data
);
1261 memset(tm
,0,sizeof(*tm
));
1263 tm
->tm_sec
= clock_data
.sec
;
1264 tm
->tm_min
= clock_data
.min
;
1265 tm
->tm_hour
= clock_data
.hour
;
1266 tm
->tm_mday
= clock_data
.mday
;
1267 tm
->tm_mon
= clock_data
.month
- 1;
1268 tm
->tm_year
= clock_data
.year
- 1900;
1271 /* Calculate the number of seconds that have passed since January 1st 1970
1272 * based upon the time specification provided. Output is in Unix format.
1275 MakeTime(const struct tm
* const tm
)
1277 struct ClockData clock_data
;
1280 clock_data
.sec
= tm
->tm_sec
;
1281 clock_data
.min
= tm
->tm_min
;
1282 clock_data
.hour
= tm
->tm_hour
;
1283 clock_data
.mday
= tm
->tm_mday
;
1284 clock_data
.month
= tm
->tm_mon
+ 1;
1285 clock_data
.year
= tm
->tm_year
+ 1900;
1287 seconds
= Date2Amiga(&clock_data
) + UNIX_TIME_OFFSET
;
1292 /****************************************************************************/
1294 struct FormatContext
1300 /****************************************************************************/
1302 #if !defined(__AROS__)
1304 CountChar(REG(a3
,struct FormatContext
* fc
))
1306 STATIC VOID
CountChar(struct FormatContext
* fc
)
1312 /* Count the number of characters SPrintf() would put into a string. */
1314 CVSPrintf(STRPTR format_string
,APTR args
)
1316 struct FormatContext fc
;
1320 RawDoFmt((STRPTR
)format_string
,args
,(VOID (*)())CountChar
,&fc
);
1325 /****************************************************************************/
1327 #if !defined(__AROS__)
1329 StuffChar(REG(d0
,UBYTE c
),REG(a3
,struct FormatContext
* fc
))
1331 STATIC VOID
StuffChar(UBYTE c
, struct FormatContext
* fc
)
1334 (*fc
->fc_Buffer
++) = c
;
1338 VSPrintf(STRPTR buffer
, STRPTR formatString
, APTR args
)
1340 struct FormatContext fc
;
1342 fc
.fc_Buffer
= buffer
;
1344 RawDoFmt(formatString
,args
,(VOID (*)())StuffChar
,&fc
);
1347 /****************************************************************************/
1349 #if !defined(__AROS__)
1350 /* Format a string for output. */
1352 SPrintf(STRPTR buffer
, STRPTR formatString
,...)
1356 #if defined(__amigaos4__)
1358 va_startlinear(varArgs
,formatString
);
1359 VSPrintf(buffer
,formatString
,va_getlinearva(varArgs
,APTR
));
1364 va_start(varArgs
,formatString
);
1365 VSPrintf(buffer
,formatString
,varArgs
);
1368 #endif /* __amigaos4__ */
1372 /****************************************************************************/
1374 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
1375 * Thanks much, Chris!
1379 unsigned short flags
;
1380 unsigned char address
[4];
1385 unsigned short name_trn_id
;
1386 unsigned short flags
;
1387 unsigned short qdcount
;
1388 unsigned short ancount
;
1389 unsigned short nscount
;
1390 unsigned short arcount
;
1394 L1_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
)
1400 while(('\0' != name
[i
]) && (i
< 15))
1402 k
= ToUpper(name
[i
]);
1404 dst
[j
++] = 'A' + ((k
& 0xF0) >> 4);
1405 dst
[j
++] = 'A' + (k
& 0x0F);
1408 i
= 'A' + ((pad
& 0xF0) >> 4);
1409 k
= 'A' + (pad
& 0x0F);
1417 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
1418 dst
[31] = 'A' + (sfx
& 0x0F);
1425 L2_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
, const UBYTE
* scope
)
1431 if(NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
1437 if('\0' != (*scope
))
1441 for(i
= 0, j
= (lenpos
+ 1);
1442 ('.' != scope
[i
]) && ('\0' != scope
[i
]);
1445 dst
[j
] = ToUpper(scope
[i
]);
1448 dst
[lenpos
] = (UBYTE
)i
;
1452 while('.' == (*scope
++));
1461 BroadcastNameQuery(char *name
, char *scope
, UBYTE
*address
)
1463 static const UBYTE header
[12] =
1465 0x07, 0xB0, /* 1964 == 0x07B0. */
1466 0x01, 0x10, /* Binary 0 0000 0010001 0000 */
1467 0x00, 0x01, /* One name query. */
1468 0x00, 0x00, /* Zero answers. */
1469 0x00, 0x00, /* Zero authorities. */
1470 0x00, 0x00 /* Zero additional. */
1473 static const UBYTE query_tail
[4] =
1482 int option_true
= 1;
1483 struct sockaddr_in sox
;
1484 struct nmb_header nmb_header
;
1493 sock_fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1496 SHOWMSG("couldn't get the socket");
1501 if(setsockopt(sock_fd
, SOL_SOCKET
, SO_BROADCAST
, &option_true
, sizeof(option_true
)) < 0)
1503 SHOWMSG("couldn't enable the broadcast option");
1508 sox
.sin_family
= AF_INET
;
1509 sox
.sin_addr
.s_addr
= htonl(0xFFFFFFFF);
1511 s
= getservbyname("netbios-ns","udp");
1513 sox
.sin_port
= htons(s
->s_port
);
1515 sox
.sin_port
= htons(137);
1517 memcpy(buffer
, header
, (total_len
= sizeof(header
)));
1519 n
= L2_Encode(&buffer
[total_len
], name
, ' ', '\0', scope
);
1522 SHOWMSG("name encoding failed");
1528 memcpy(&buffer
[total_len
], query_tail
, sizeof(query_tail
));
1529 total_len
+= sizeof(query_tail
);
1534 /* Send the query packet; retry five times with a one second
1537 for(i
= 0 ; i
< 5 ; i
++)
1539 if(sendto(sock_fd
, (void *) buffer
, total_len
, 0, (struct sockaddr
*)&sox
, sizeof(struct sockaddr_in
)) < 0)
1541 SHOWMSG("could not send the packet");
1546 /* Wait for a response to arrive. */
1551 FD_SET(sock_fd
,&read_fds
);
1553 if(WaitSelect(sock_fd
+1, &read_fds
, NULL
, NULL
, &tv
, NULL
) > 0)
1555 n
= recvfrom(sock_fd
, buffer
, sizeof(buffer
), 0, NULL
, NULL
);
1558 SHOWMSG("could not pick up the response packet");
1569 /* Did we get anything at all? */
1570 if(n
> (int)sizeof(nmb_header
))
1572 /* Check whether the query was successful. */
1573 memcpy(&nmb_header
, buffer
, sizeof(nmb_header
));
1574 if((nmb_header
.flags
& 0xF) == OK
)
1576 /* Find the NB/IP fields which directly follow
1579 for(i
= sizeof(header
) + strlen(&buffer
[sizeof(header
)])+1 ; i
< n
- (int)sizeof(query_tail
) ; i
++)
1581 if(memcmp(&buffer
[i
], query_tail
, sizeof(query_tail
)) == SAME
)
1585 /* This should be the start of the interesting bits;
1586 * we skip the NB/IP fields and the TTL field.
1588 start
= i
+ sizeof(query_tail
) + sizeof(long);
1591 unsigned short read_len
;
1592 struct addr_entry addr_entry
;
1594 /* This should be the read length. */
1595 memcpy(&read_len
, &buffer
[start
], 2);
1597 /* Is there any useful and readable data attached? */
1598 if(read_len
>= sizeof(addr_entry
) &&
1599 start
+ (int)sizeof(read_len
) + (int)sizeof(addr_entry
) <= n
)
1601 /* Copy a single address entry; this should be
1602 * just the one we need.
1604 memcpy(&addr_entry
, &buffer
[start
+ sizeof(read_len
)], sizeof(addr_entry
));
1606 /* Copy the address field (IPv4 only). */
1607 memcpy(address
, addr_entry
.address
, 4);
1622 CloseSocket(sock_fd
);
1628 /****************************************************************************/
1630 /* Send a disk change notification message which will be picked up
1631 * by all applications that listen for this kind of event, e.g.
1635 SendDiskChange(ULONG
class)
1637 struct IOStdReq
* input_request
= NULL
;
1638 struct MsgPort
* input_port
;
1639 struct InputEvent ie
;
1643 input_port
= CreateMsgPort();
1644 if(input_port
== NULL
)
1647 input_request
= (struct IOStdReq
*)CreateIORequest(input_port
,sizeof(*input_request
));
1648 if(input_request
== NULL
)
1651 if(OpenDevice("input.device",0,(struct IORequest
*)input_request
,0) != OK
)
1654 memset(&ie
,0,sizeof(ie
));
1656 ie
.ie_Class
= class;
1657 ie
.ie_Qualifier
= IEQUALIFIER_MULTIBROADCAST
;
1659 GetSysTime(&ie
.ie_TimeStamp
);
1661 input_request
->io_Command
= IND_WRITEEVENT
;
1662 input_request
->io_Data
= &ie
;
1663 input_request
->io_Length
= sizeof(ie
);
1665 DoIO((struct IORequest
*)input_request
);
1669 if(input_request
!= NULL
)
1671 if(input_request
->io_Device
!= NULL
)
1672 CloseDevice((struct IORequest
*)input_request
);
1674 DeleteIORequest((struct IORequest
*)input_request
);
1677 DeleteMsgPort(input_port
);
1682 /****************************************************************************/
1684 /* Find the file node corresponding to a given name,
1685 * skipping a particular entry if necessary.
1687 STATIC
struct FileNode
*
1688 FindFileNode(STRPTR name
,struct FileNode
* skip
)
1690 struct FileNode
* result
= NULL
;
1691 struct FileNode
* fn
;
1693 for(fn
= (struct FileNode
*)FileList
.mlh_Head
;
1694 fn
->fn_MinNode
.mln_Succ
!= NULL
;
1695 fn
= (struct FileNode
*)fn
->fn_MinNode
.mln_Succ
)
1697 if(fn
!= skip
&& CompareNames(name
,fn
->fn_FullName
) == SAME
)
1707 /* Find the lock node corresponding to a given name,
1708 * skipping a particular entry if necessary.
1710 STATIC
struct LockNode
*
1711 FindLockNode(STRPTR name
,struct LockNode
* skip
)
1713 struct LockNode
* result
= NULL
;
1714 struct LockNode
* ln
;
1716 for(ln
= (struct LockNode
*)LockList
.mlh_Head
;
1717 ln
->ln_MinNode
.mln_Succ
!= NULL
;
1718 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
1720 if(ln
!= skip
&& CompareNames(name
,ln
->ln_FullName
) == SAME
)
1730 /* Check whether a new reference to be made to a named
1731 * file will cause a conflict of access modes. No two
1732 * files and locks may refer to the same object if
1733 * either of these references is made in exclusive
1734 * mode. This is the case which this function is
1738 CheckAccessModeCollision(STRPTR name
,LONG mode
)
1740 struct LockNode
* ln
;
1741 struct FileNode
* fn
;
1747 fn
= FindFileNode(name
,NULL
);
1750 if(mode
!= SHARED_LOCK
|| fn
->fn_Mode
!= SHARED_LOCK
)
1752 D(("collides with '%s'",fn
->fn_FullName
));
1753 error
= ERROR_OBJECT_IN_USE
;
1758 ln
= FindLockNode(name
,NULL
);
1761 if(mode
!= SHARED_LOCK
|| ln
->ln_FileLock
.fl_Access
!= SHARED_LOCK
)
1763 D(("collides with '%s'",ln
->ln_FullName
));
1764 error
= ERROR_OBJECT_IN_USE
;
1775 /* Find out whether there already exists a reference to a
1776 * certain file or directory.
1779 NameAlreadyInUse(STRPTR name
)
1785 if(FindFileNode(name
,NULL
) != NULL
)
1787 error
= ERROR_OBJECT_IN_USE
;
1791 if(FindLockNode(name
,NULL
) != NULL
)
1793 error
= ERROR_OBJECT_IN_USE
;
1803 /* Check whether an Amiga file name uses special characters which
1804 * should be avoided when used with the SMB file sharing protocol.
1807 IsReservedName(STRPTR name
)
1809 BOOL result
= FALSE
;
1811 /* Disallow "." and "..". */
1812 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
1820 /* Disallow the use of the backslash in file names. */
1821 while((c
= (*name
++)) != '\0')
1823 if(c
== SMB_PATH_SEPARATOR
)
1834 /****************************************************************************/
1836 /* Convert a POSIX error code into an AmigaDOS error code. */
1838 MapErrnoToIoErr(int error
)
1840 /* Not all of these mappings make good sense; bear in mind that
1841 * POSIX covers more than a hundred different error codes
1842 * whereas with AmigaDOS we're stranded with a measly 48...
1844 STATIC
const LONG Map
[][2] =
1846 { EPERM
, ERROR_OBJECT_NOT_FOUND
}, /* Operation not permitted */
1847 { ENOENT
, ERROR_OBJECT_NOT_FOUND
}, /* No such file or directory */
1848 { ESRCH
, ERROR_OBJECT_NOT_FOUND
}, /* No such process */
1849 { EINTR
, ERROR_BREAK
}, /* Interrupted system call */
1850 { EIO
, ERROR_OBJECT_IN_USE
}, /* Input/output error */
1851 { E2BIG
, ERROR_TOO_MANY_ARGS
}, /* Argument list too long */
1852 { EBADF
, ERROR_INVALID_LOCK
}, /* Bad file descriptor */
1853 { ENOMEM
, ERROR_NO_FREE_STORE
}, /* Cannot allocate memory */
1854 { EACCES
, ERROR_OBJECT_IN_USE
}, /* Permission denied */
1856 { ENOTBLK
, ERROR_OBJECT_WRONG_TYPE
}, /* Block device required */
1858 { EBUSY
, ERROR_OBJECT_IN_USE
}, /* Device busy */
1859 { EEXIST
, ERROR_OBJECT_EXISTS
}, /* File exists */
1860 { EXDEV
, ERROR_NOT_IMPLEMENTED
}, /* Cross-device link */
1861 { ENOTDIR
, ERROR_OBJECT_WRONG_TYPE
}, /* Not a directory */
1862 { EISDIR
, ERROR_OBJECT_WRONG_TYPE
}, /* Is a directory */
1863 { EINVAL
, ERROR_BAD_NUMBER
}, /* Invalid argument */
1864 { EFBIG
, ERROR_DISK_FULL
}, /* File too large */
1865 { ENOSPC
, ERROR_DISK_FULL
}, /* No space left on device */
1866 { ESPIPE
, ERROR_SEEK_ERROR
}, /* Illegal seek */
1867 { EROFS
, ERROR_WRITE_PROTECTED
}, /* Read-only file system */
1868 { EMLINK
, ERROR_TOO_MANY_LEVELS
}, /* Too many links */
1869 { ENOTSOCK
, ERROR_OBJECT_WRONG_TYPE
}, /* Socket operation on non-socket */
1870 { EDESTADDRREQ
, ERROR_REQUIRED_ARG_MISSING
}, /* Destination address required */
1871 { EMSGSIZE
, ERROR_LINE_TOO_LONG
}, /* Message too long */
1872 { EPROTOTYPE
, ERROR_BAD_TEMPLATE
}, /* Protocol wrong type for socket */
1873 { ENOPROTOOPT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol not available */
1874 { EPROTONOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol not supported */
1875 { ESOCKTNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Socket type not supported */
1876 { EOPNOTSUPP
, ERROR_NOT_IMPLEMENTED
}, /* Operation not supported */
1877 { EPFNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol family not supported */
1878 { EAFNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Address family not supported by protocol family */
1879 { EADDRINUSE
, ERROR_OBJECT_IN_USE
}, /* Address already in use */
1880 { EADDRNOTAVAIL
, ERROR_OBJECT_NOT_FOUND
}, /* Can't assign requested address */
1881 { ENETDOWN
, ERROR_OBJECT_NOT_FOUND
}, /* Network is down */
1882 { ENETUNREACH
, ERROR_OBJECT_NOT_FOUND
}, /* Network is unreachable */
1883 { ENETRESET
, ERROR_OBJECT_NOT_FOUND
}, /* Network dropped connection on reset */
1884 { ECONNABORTED
, ERROR_OBJECT_NOT_FOUND
}, /* Software caused connection abort */
1885 { ECONNRESET
, ERROR_OBJECT_NOT_FOUND
}, /* Connection reset by peer */
1886 { ENOBUFS
, ERROR_DISK_FULL
}, /* No buffer space available */
1887 { EISCONN
, ERROR_OBJECT_IN_USE
}, /* Socket is already connected */
1888 { ENOTCONN
, ERROR_OBJECT_WRONG_TYPE
}, /* Socket is not connected */
1889 { ESHUTDOWN
, ERROR_INVALID_LOCK
}, /* Can't send after socket shutdown */
1890 { ECONNREFUSED
, ERROR_OBJECT_IN_USE
}, /* Connection refused */
1891 { ELOOP
, ERROR_TOO_MANY_LEVELS
}, /* Too many levels of symbolic links */
1892 { ENAMETOOLONG
, ERROR_LINE_TOO_LONG
}, /* File name too long */
1893 { EHOSTDOWN
, ERROR_OBJECT_NOT_FOUND
}, /* Host is down */
1894 { EHOSTUNREACH
, ERROR_OBJECT_NOT_FOUND
}, /* No route to host */
1895 { ENOTEMPTY
, ERROR_DIRECTORY_NOT_EMPTY
}, /* Directory not empty */
1896 { EPROCLIM
, ERROR_TASK_TABLE_FULL
}, /* Too many processes */
1898 { EUSERS
, ERROR_TASK_TABLE_FULL
}, /* Too many users */
1900 { EDQUOT
, ERROR_DISK_FULL
}, /* Disc quota exceeded */
1901 { ENOLCK
, ERROR_NOT_IMPLEMENTED
}, /* no locks available */
1905 LONG result
= ERROR_ACTION_NOT_KNOWN
;
1913 for(i
= 0 ; Map
[i
][0] != -1 ; i
++)
1915 if(Map
[i
][0] == error
)
1926 /****************************************************************************/
1928 /* Translate a BCPL style file name (i.e. length is in the first byte)
1929 * via a mapping table.
1932 TranslateBName(UBYTE
* name
,UBYTE
* map
)
1939 #if !defined(__AROS__)
1942 len
= AROS_BSTR_strlen(name
);
1943 name
= AROS_BSTR_ADDR(name
);
1954 /* Translate a NUL terminated file name via a mapping table. */
1956 TranslateCName(UBYTE
* name
,UBYTE
* map
)
1962 while((c
= (*name
)) != '\0')
1967 /****************************************************************************/
1969 /* Remove a DosList entry using the proper protocols. Note that
1970 * this function can fail!
1973 ReallyRemoveDosEntry(struct DosList
* entry
)
1975 struct Message
* mn
;
1976 struct MsgPort
* port
;
1977 struct DosList
* dl
;
1978 BOOL result
= FALSE
;
1981 if(entry
->dol_Type
== DLT_DEVICE
)
1986 port
= entry
->dol_Task
;
1988 for(i
= 0 ; i
< 100 ; i
++)
1990 dl
= AttemptLockDosList(LDF_WRITE
|kind
);
1998 UnLockDosList(LDF_WRITE
|kind
);
2005 while((mn
= GetMsg(port
)) != NULL
)
2006 ReplyPkt((struct DosPacket
*)mn
->mn_Node
.ln_Name
,DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
2008 Delay(TICKS_PER_SECOND
/ 10);
2014 /****************************************************************************/
2016 /* Release all resources allocated by the Setup() routine. */
2020 BOOL send_disk_change
= FALSE
;
2024 /* If any errors have cropped up, display them now before
2029 if(NewProgramName
!= NULL
)
2031 FreeVec(NewProgramName
);
2032 NewProgramName
= NULL
;
2035 if(Parameters
!= NULL
)
2037 FreeArgs(Parameters
);
2043 FreeDiskObject(Icon
);
2047 if(ServerData
!= NULL
)
2049 smba_disconnect(ServerData
);
2053 if(DeviceNode
!= NULL
)
2057 if(ReallyRemoveDosEntry(DeviceNode
))
2058 FreeDosEntry(DeviceNode
);
2062 FreeDosEntry(DeviceNode
);
2068 if(VolumeNode
!= NULL
)
2072 if(ReallyRemoveDosEntry(VolumeNode
))
2073 FreeDosEntry(VolumeNode
);
2075 send_disk_change
= TRUE
;
2079 FreeDosEntry(VolumeNode
);
2085 if(FileSystemPort
!= NULL
)
2087 struct Message
* mn
;
2089 /* Return all queued packets; there should be none, though. */
2090 while((mn
= GetMsg(FileSystemPort
)) != NULL
)
2091 ReplyPkt((struct DosPacket
*)mn
->mn_Node
.ln_Name
,DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
2093 DeleteMsgPort(FileSystemPort
);
2094 FileSystemPort
= NULL
;
2097 if(WBStartup
== NULL
&& send_disk_change
)
2098 SendDiskChange(IECLASS_DISKREMOVED
);
2100 #if defined(__amigaos4__)
2104 DropInterface((struct Interface
*)ITimer
);
2108 #endif /* __amigaos4__ */
2110 if(TimerBase
!= NULL
)
2112 CloseDevice((struct IORequest
*)&TimerRequest
);
2116 #if defined(__amigaos4__)
2120 DropInterface((struct Interface
*)ISocket
);
2124 #endif /* __amigaos4__ */
2126 if(SocketBase
!= NULL
)
2128 CloseLibrary(SocketBase
);
2132 #if defined(__amigaos4__)
2134 if(IUtility
!= NULL
)
2136 DropInterface((struct Interface
*)IUtility
);
2140 #endif /* __amigaos4__ */
2142 if(UtilityBase
!= NULL
)
2144 CloseLibrary(UtilityBase
);
2148 #if defined(__amigaos4__)
2152 DropInterface((struct Interface
*)IIcon
);
2156 #endif /* __amigaos4__ */
2158 if(IconBase
!= NULL
)
2160 CloseLibrary(IconBase
);
2166 CloseLocale(Locale
);
2170 #if defined(__amigaos4__)
2174 DropInterface((struct Interface
*)ILocale
);
2178 #endif /* __amigaos4__ */
2180 if(LocaleBase
!= NULL
)
2182 CloseLibrary(LocaleBase
);
2186 if(MemoryPool
!= NULL
)
2188 DeletePool(MemoryPool
);
2192 #if defined(__amigaos4__)
2196 DropInterface((struct Interface
*)IDOS
);
2200 #endif /* __amigaos4__ */
2204 CloseLibrary(DOSBase
);
2208 if(WBStartup
!= NULL
)
2211 ReplyMsg((struct Message
*)WBStartup
);
2217 /* Allocate all the necessary resources to get going. */
2220 STRPTR program_name
,
2224 STRPTR opt_password
,
2225 BOOL opt_changecase
,
2226 STRPTR opt_clientname
,
2227 STRPTR opt_servername
,
2229 LONG
* opt_time_zone_offset
,
2230 LONG
* opt_dst_offset
,
2233 STRPTR translation_file
)
2235 BOOL result
= FALSE
;
2236 struct DosList
* dl
;
2238 STRPTR actual_volume_name
;
2239 LONG actual_volume_name_len
;
2240 UBYTE name
[MAX_FILENAME_LEN
];
2241 BOOL device_exists
= FALSE
;
2246 NewList((struct List
*)&FileList
);
2247 NewList((struct List
*)&LockList
);
2249 MemoryPool
= CreatePool(MEMF_ANY
|MEMF_PUBLIC
,4096,4096);
2250 if(MemoryPool
== NULL
)
2252 ReportError("Could not create memory pool.");
2256 LocaleBase
= OpenLibrary("locale.library",38);
2258 #if defined(__amigaos4__)
2260 if(LocaleBase
!= NULL
)
2262 ILocale
= (struct LocaleIFace
*)GetInterface(LocaleBase
, "main", 1, 0);
2265 CloseLibrary(LocaleBase
);
2270 #endif /* __amigaos4__ */
2272 if(LocaleBase
!= NULL
)
2273 Locale
= OpenLocale(NULL
);
2275 if(opt_time_zone_offset
!= NULL
)
2277 TimeZoneOffset
= (*opt_time_zone_offset
);
2278 OverrideLocaleTimeZone
= TRUE
;
2281 if(opt_dst_offset
!= NULL
)
2282 DSTOffset
= -60 * (*opt_dst_offset
);
2284 memset(&TimerRequest
,0,sizeof(TimerRequest
));
2286 if(OpenDevice(TIMERNAME
,UNIT_VBLANK
,(struct IORequest
*)&TimerRequest
,0) != OK
)
2288 ReportError("Could not open 'timer.device'.");
2292 TimerBase
= (struct Library
*)TimerRequest
.tr_node
.io_Device
;
2294 #if defined(__amigaos4__)
2296 if(TimerBase
!= NULL
)
2298 ITimer
= (struct TimerIFace
*)GetInterface(TimerBase
, "main", 1, 0);
2301 ReportError("Could not open 'timer.device'.");
2306 #endif /* __amigaos4__ */
2308 SocketBase
= OpenLibrary("bsdsocket.library",3);
2310 #if defined(__amigaos4__)
2312 if(SocketBase
!= NULL
)
2314 ISocket
= (struct SocketIFace
*)GetInterface(SocketBase
, "main", 1, 0);
2317 CloseLibrary(SocketBase
);
2322 #endif /* __amigaos4__ */
2324 if(SocketBase
== NULL
)
2326 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
2330 error
= SocketBaseTags(
2331 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno
))), &errno
,
2332 SBTM_SETVAL(SBTC_HERRNOLONGPTR
), &h_errno
,
2333 SBTM_SETVAL(SBTC_LOGTAGPTR
), program_name
,
2334 SBTM_SETVAL(SBTC_BREAKMASK
), SIGBREAKF_CTRL_C
,
2338 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error
,amitcp_strerror(error
));
2344 for(i
= 0 ; i
< (LONG
)strlen(opt_password
) ; i
++)
2345 opt_password
[i
] = ToUpper(opt_password
[i
]);
2348 TranslateNames
= FALSE
;
2350 /* Read the translation file, if possible. */
2351 if(translation_file
!= NULL
)
2358 file
= Open(translation_file
,MODE_OLDFILE
);
2361 if(Read(file
,A2M
,256) != 256 ||
2362 Read(file
,M2A
,256) != 256)
2364 msg
= "Could not read translation file";
2372 msg
= "Could not open translation file";
2378 TranslateNames
= TRUE
;
2382 UBYTE description
[100];
2384 Fault(error
,NULL
,description
,sizeof(description
));
2385 for(i
= ((int)strlen(description
)) - 1 ; i
>= 0 ; i
--)
2387 if(description
[i
] == '\n')
2388 description
[i
] = '\0';
2391 ReportError("%s '%s' (%ld, %s).",msg
,translation_file
,error
,description
);
2396 error
= smba_start(service
,workgroup
,username
,opt_password
,opt_clientname
,opt_servername
,opt_cachesize
,&ServerData
);
2400 FileSystemPort
= CreateMsgPort();
2401 if(FileSystemPort
== NULL
)
2403 ReportError("Could not create filesystem port.");
2407 /* If a device name was provided, check whether it is
2410 if(device_name
!= NULL
)
2412 len
= strlen(device_name
);
2416 for(i
= 0 ; i
< len
; i
++)
2418 if(device_name
[i
] == '/')
2420 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
2425 /* Lose any trailing colon characters. */
2426 for(i
= len
-1 ; i
>= 0 ; i
--)
2428 if(device_name
[i
] == ':')
2434 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name
);
2438 memcpy(name
,device_name
,len
);
2441 dl
= LockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2443 if(FindDosEntry(dl
,name
,LDF_DEVICES
) != NULL
)
2444 device_exists
= TRUE
;
2448 dl
= LockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2450 /* Find a unique device name. */
2451 for(i
= 0 ; i
< 100 ; i
++)
2453 SPrintf(name
,"SMBFS%ld",i
);
2455 device_exists
= (BOOL
)(FindDosEntry(dl
,name
,LDF_DEVICES
) != NULL
);
2456 if(NOT device_exists
)
2466 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2468 ReportError("Device name '%s:' is already taken.",device_name
);
2472 /* Finally, create the device node. */
2473 DeviceNode
= MakeDosEntry(name
,DLT_DEVICE
);
2474 if(DeviceNode
== NULL
)
2476 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2478 ReportError("Could not create device node.");
2482 DeviceNode
->dol_Task
= FileSystemPort
;
2484 /* Examine the volume name; make sure that it is
2487 if(volume_name
== NULL
)
2488 actual_volume_name
= device_name
;
2490 actual_volume_name
= volume_name
;
2492 actual_volume_name_len
= strlen(actual_volume_name
);
2493 if(actual_volume_name_len
> 255)
2494 actual_volume_name_len
= 255;
2496 for(i
= 0 ; i
< actual_volume_name_len
; i
++)
2498 if(actual_volume_name
[i
] == '/')
2500 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2502 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
2507 /* Lose any trailing colon characters. */
2508 for(i
= actual_volume_name_len
-1 ; i
>= 0 ; i
--)
2510 if(actual_volume_name
[i
] == ':')
2511 actual_volume_name_len
= i
;
2514 if(actual_volume_name_len
== 0)
2516 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2518 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
2522 /* Now, finally, take care of the volume name. */
2523 memcpy(name
,actual_volume_name
,actual_volume_name_len
);
2524 name
[actual_volume_name_len
] = '\0';
2526 VolumeNode
= MakeDosEntry(name
,DLT_VOLUME
);
2527 if(VolumeNode
== NULL
)
2529 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2531 ReportError("Could not create volume node.");
2535 VolumeNode
->dol_Task
= FileSystemPort
;
2536 DateStamp(&VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
);
2537 VolumeNode
->dol_misc
.dol_volume
.dol_DiskType
= ID_DOS_DISK
;
2539 if(DeviceNode
!= NULL
)
2541 AddDosEntry(DeviceNode
);
2543 DeviceNodeAdded
= TRUE
;
2546 /* Note: we always need the volume node to make some file
2547 * system operations safe (e.g. Lock()), but we may
2548 * not always need to make it visible.
2550 if(volume_name
!= NULL
&& VolumeNode
!= NULL
)
2552 AddDosEntry(VolumeNode
);
2554 VolumeNodeAdded
= TRUE
;
2557 /* And that concludes the mounting operation. */
2558 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
|LDF_DEVICES
);
2560 /* Tell Workbench and friends to update their volume lists. */
2562 SendDiskChange(IECLASS_DISKINSERTED
);
2564 SetProgramName(NewProgramName
);
2574 /****************************************************************************/
2577 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
2578 #if !defined(__AROS__)
2580 ConvertBString(LONG max_len
,STRPTR cstring
,APTR bstring
)
2582 STRPTR from
= bstring
;
2589 memcpy(cstring
,from
+1,len
);
2591 cstring
[len
] = '\0';
2595 ConvertBString(LONG max_len
,STRPTR cstring
,APTR bstring
)
2598 UWORD _len
= AROS_BSTR_strlen(bstring
);
2600 while((_i
< _len
) && (_i
< max_len
))
2602 cstring
[_i
] = AROS_BSTR_getchar(bstring
, _i
);
2610 /* Convert a NUL terminated 'C' string into a BCPL string. */
2611 #if !defined(__AROS__)
2613 ConvertCString(LONG max_len
, APTR bstring
, STRPTR cstring
)
2615 LONG len
= strlen(cstring
);
2616 STRPTR to
= bstring
;
2622 memcpy(to
,cstring
,len
);
2626 ConvertCString(LONG max_len
, APTR bstring
, STRPTR cstring
)
2629 while((cstring
[_i
] != '\0') && (_i
< max_len
))
2631 AROS_BSTR_putchar(bstring
, _i
, cstring
[_i
]);
2634 AROS_BSTR_setstrlen(bstring
, _i
);
2638 /****************************************************************************/
2640 /* Build the fully qualified name of a file or directory in reference
2641 * to the name of the parent directory. This takes care of all the
2642 * special cases, such as the root directory. The result will be converted
2643 * to be in a form suitable for use with the SMB file sharing service.
2649 STRPTR
* result_ptr
,
2650 LONG
* result_size_ptr
)
2659 SHOWSTRING(parent_name
);
2662 (*result_ptr
) = NULL
;
2664 /* Throw everything left of the colon away. */
2667 for(i
= 0 ; i
< (LONG
)strlen(name
) ; i
++)
2677 /* Now, how much room is needed for the complete
2678 * path to fit into a buffer?
2682 if(parent_name
!= NULL
)
2683 len
+= strlen(parent_name
) + 1;
2686 len
+= strlen(name
) + 1;
2688 if(len
< SMB_MAXNAMELEN
)
2689 len
= SMB_MAXNAMELEN
;
2693 buffer
= AllocateMemory(size
);
2696 error
= ERROR_NO_FREE_STORE
;
2700 /* Start by filling in the path name. */
2701 if(parent_name
!= NULL
)
2703 /* Skip any excess separators. */
2704 while((*parent_name
) == SMB_PATH_SEPARATOR
)
2707 buffer
[0] = SMB_PATH_SEPARATOR
;
2708 strcpy(&buffer
[1],parent_name
);
2712 strcpy(buffer
,SMB_ROOT_DIR_NAME
);
2715 /* If there's a name to add, do just that. */
2723 buffer_len
= strlen(buffer
);
2724 name_len
= strlen(name
);
2732 /* Extract the next path name segment. */
2733 for(i
= segment_start
; i
<= name_len
; i
++)
2737 segment_len
= i
- segment_start
;
2740 else if (name
[i
] == '/')
2742 segment_len
= i
- segment_start
+ 1;
2747 /* We're finished if there are no further
2748 * path name segments to take care of.
2750 if(segment_len
== 0)
2752 buffer
[buffer_len
] = '\0';
2756 /* A single slash indicates that we need to move up
2757 * to the parent directory, if any.
2759 if(segment_len
== 1 && name
[segment_start
] == '/')
2761 /* Is this already the root directory name? */
2771 /* Skip the last path component. */
2772 for(i
= 1 ; i
<= buffer_len
; i
++)
2776 /* We just skipped the first path
2777 * component following the root
2778 * directory name. We preserve
2779 * the first character since it
2780 * refers to the root directory.
2785 else if (buffer
[buffer_len
-i
] == SMB_PATH_SEPARATOR
)
2787 /* This removes both the path separator and
2788 * the name following it.
2798 /* Add a proper separator character if
2801 if(buffer_len
> 0 && buffer
[buffer_len
-1] != SMB_PATH_SEPARATOR
)
2802 buffer
[buffer_len
++] = SMB_PATH_SEPARATOR
;
2804 /* Find out how many characters are in that name; this
2805 * excludes the terminating slash.
2807 if(name
[segment_start
+ segment_len
- 1] == '/')
2808 len
= segment_len
- 1;
2812 memcpy(&buffer
[buffer_len
],&name
[segment_start
],len
);
2816 segment_start
+= segment_len
;
2820 (*result_ptr
) = buffer
;
2821 (*result_size_ptr
) = size
;
2834 /****************************************************************************/
2838 struct FileLock
* parent
,
2842 STRPTR full_name
= NULL
;
2843 LONG full_name_size
;
2845 BOOL cleanup
= TRUE
;
2846 struct LockNode
* ln
= NULL
;
2855 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2857 parent_name
= parent_ln
->ln_FullName
;
2864 error
= BuildFullName(parent_name
,"/",&full_name
,&full_name_size
);
2868 /* Check if we ended up having to return the parent of
2869 * the root directory. This is indicated by a NULL
2870 * name pointer and a zero error code.
2872 if(full_name
== NULL
)
2875 ln
= AllocateMemory(sizeof(*ln
));
2878 error
= ERROR_NO_FREE_STORE
;
2882 memset(ln
,0,sizeof(*ln
));
2884 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2885 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
2886 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2887 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2888 ln
->ln_FullName
= full_name
;
2890 SHOWSTRING(full_name
);
2892 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2895 error
= MapErrnoToIoErr(error
);
2899 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2900 result
= MKBADDR(&ln
->ln_FileLock
);
2902 SHOWVALUE(&ln
->ln_FileLock
);
2908 FreeMemory(full_name
);
2912 (*error_ptr
) = error
;
2918 /****************************************************************************/
2920 /* Find the lock node corresponding to a given name,
2921 * starting from node start. (if node, this one is skipped)
2923 STATIC
struct LockNode
*
2924 FindNextLockNode(STRPTR name
,struct LockNode
* last_ln
)
2926 struct LockNode
* result
= NULL
;
2927 struct LockNode
* ln
;
2928 struct LockNode
* start
;
2931 start
= (struct LockNode
*)last_ln
->ln_MinNode
.mln_Succ
;
2933 start
= (struct LockNode
*)LockList
.mlh_Head
;
2936 ln
->ln_MinNode
.mln_Succ
!= NULL
;
2937 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
2939 if(CompareNames(name
,ln
->ln_FullName
) == SAME
)
2949 /****************************************************************************/
2952 Action_DeleteObject(
2953 struct FileLock
* parent
,
2957 LONG result
= DOSFALSE
;
2958 STRPTR full_name
= NULL
;
2959 LONG full_name_size
;
2960 smba_file_t
* file
= NULL
;
2962 STRPTR full_parent_name
= NULL
;
2963 UBYTE name
[MAX_FILENAME_LEN
];
2964 struct LockNode
* ln
;
2972 error
= ERROR_DISK_WRITE_PROTECTED
;
2980 ln
= (struct LockNode
*)parent
->fl_Key
;
2982 parent_name
= ln
->ln_FullName
;
2989 ConvertBString(sizeof(name
),name
,bcpl_name
);
2990 TranslateCName(name
,A2M
);
2992 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2996 /* Trying to delete the root directory, are you kidding? */
2997 if(full_name
== NULL
)
2999 error
= ERROR_OBJECT_WRONG_TYPE
;
3003 /* We need to find this file's parent directory, so that
3004 * in case the directory contents are currently being
3005 * examined, that process is restarted.
3007 full_parent_name
= AllocateMemory(strlen(full_name
)+3);
3008 if(full_parent_name
== NULL
)
3010 error
= ERROR_NO_FREE_STORE
;
3014 strcpy(full_parent_name
,full_name
);
3016 /* Build the parent object name - Piru */
3017 if (full_parent_name
[0] != '\0')
3021 i
= strlen(full_parent_name
) - 1;
3022 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
3025 for ( ; i
>= 0 ; i
--)
3027 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
3029 full_parent_name
[i
] = '\0';
3035 /* NOTE: Mark all locks to this object as restart, not just first
3038 while ((ln
= FindNextLockNode(full_parent_name
, ln
)) != NULL
)
3039 ln
->ln_RestartExamine
= TRUE
;
3041 ln
= FindLockNode(full_parent_name
,NULL
);
3043 ln
->ln_RestartExamine
= TRUE
;
3045 FreeMemory(full_parent_name
);
3046 full_parent_name
= NULL
;
3048 SHOWSTRING(full_name
);
3050 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
3053 error
= MapErrnoToIoErr(error
);
3057 error
= smba_getattr(file
,&st
);
3060 error
= MapErrnoToIoErr(error
);
3069 SHOWMSG("removing a directory");
3071 error
= smba_rmdir(ServerData
,full_name
);
3076 /* This is a little bit difficult to justify since
3077 * the error code may indicate a different cause,
3078 * but in practice 'EACCES' seems to be returned
3079 * if the directory to remove is not empty.
3081 if(error
== (-EACCES
))
3082 error
= ERROR_DIRECTORY_NOT_EMPTY
;
3084 error
= MapErrnoToIoErr(error
);
3091 SHOWMSG("removing a file");
3093 error
= smba_remove(ServerData
,full_name
);
3098 error
= MapErrnoToIoErr(error
);
3109 FreeMemory(full_name
);
3110 FreeMemory(full_parent_name
);
3114 (*error_ptr
) = error
;
3120 /****************************************************************************/
3124 struct FileLock
* parent
,
3129 STRPTR full_name
= NULL
;
3130 LONG full_name_size
;
3131 struct LockNode
* ln
= NULL
;
3133 STRPTR dir_name
= NULL
;
3134 smba_file_t
* dir
= NULL
;
3136 UBYTE name
[MAX_FILENAME_LEN
];
3144 error
= ERROR_DISK_WRITE_PROTECTED
;
3152 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
3154 parent_name
= parent_ln
->ln_FullName
;
3161 ConvertBString(sizeof(name
),name
,bcpl_name
);
3162 TranslateCName(name
,A2M
);
3164 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3168 /* Trying to overwrite the root directory, are you kidding? */
3169 if(full_name
== NULL
)
3171 error
= ERROR_OBJECT_IN_USE
;
3175 dir_name
= AllocateMemory(strlen(full_name
)+3);
3176 if(dir_name
== NULL
)
3178 error
= ERROR_NO_FREE_STORE
;
3182 strcpy(dir_name
,full_name
);
3184 for(i
= strlen(dir_name
)-1 ; i
>= 0 ; i
--)
3186 if(dir_name
[i
] == SMB_PATH_SEPARATOR
)
3190 memmove(&dir_name
[1],&dir_name
[0],strlen(dir_name
)+1);
3196 base_name
= &dir_name
[i
+1];
3201 ln
= AllocateMemory(sizeof(*ln
));
3204 error
= ERROR_NO_FREE_STORE
;
3208 memset(ln
,0,sizeof(*ln
));
3210 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
3211 ln
->ln_FileLock
.fl_Access
= EXCLUSIVE_LOCK
;
3212 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
3213 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
3214 ln
->ln_FullName
= full_name
;
3216 error
= smba_open(ServerData
,dir_name
,strlen(full_name
)+3,&dir
);
3219 error
= MapErrnoToIoErr(error
);
3223 error
= smba_mkdir(dir
,base_name
);
3226 error
= MapErrnoToIoErr(error
);
3233 SHOWSTRING(full_name
);
3235 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3238 error
= MapErrnoToIoErr(error
);
3242 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3243 result
= MKBADDR(&ln
->ln_FileLock
);
3244 SHOWVALUE(&ln
->ln_FileLock
);
3251 FreeMemory(dir_name
);
3255 FreeMemory(full_name
);
3259 (*error_ptr
) = error
;
3265 /****************************************************************************/
3268 Action_LocateObject(
3269 struct FileLock
* parent
,
3275 STRPTR full_name
= NULL
;
3276 LONG full_name_size
;
3277 struct LockNode
* ln
= NULL
;
3279 UBYTE name
[MAX_FILENAME_LEN
];
3288 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
3290 parent_name
= parent_ln
->ln_FullName
;
3297 ConvertBString(sizeof(name
),name
,bcpl_name
);
3298 TranslateCName(name
,A2M
);
3300 if(IsReservedName(FilePart(name
)))
3302 error
= ERROR_OBJECT_NOT_FOUND
;
3306 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3310 /* Trying to get a lock on the root directory's parent?
3313 if(full_name
== NULL
)
3316 ln
= AllocateMemory(sizeof(*ln
));
3319 error
= ERROR_NO_FREE_STORE
;
3323 memset(ln
,0,sizeof(*ln
));
3325 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
3326 ln
->ln_FileLock
.fl_Access
= (mode
!= EXCLUSIVE_LOCK
) ? SHARED_LOCK
: EXCLUSIVE_LOCK
;
3327 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
3328 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
3329 ln
->ln_FullName
= full_name
;
3331 error
= CheckAccessModeCollision(full_name
,ln
->ln_FileLock
.fl_Access
);
3335 SHOWSTRING(full_name
);
3337 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3340 error
= MapErrnoToIoErr(error
);
3344 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3345 result
= MKBADDR(&ln
->ln_FileLock
);
3346 SHOWVALUE(&ln
->ln_FileLock
);
3352 FreeMemory(full_name
);
3356 (*error_ptr
) = error
;
3362 /****************************************************************************/
3366 struct FileLock
* lock
,
3370 STRPTR full_name
= NULL
;
3371 LONG full_name_size
;
3372 struct LockNode
* ln
= NULL
;
3381 if(lock
!= NULL
&& lock
->fl_Access
!= SHARED_LOCK
)
3383 SHOWMSG("cannot duplicate exclusive lock");
3384 error
= ERROR_OBJECT_IN_USE
;
3388 ln
= AllocateMemory(sizeof(*ln
));
3391 error
= ERROR_NO_FREE_STORE
;
3395 memset(ln
,0,sizeof(*ln
));
3399 struct LockNode
* source
= (struct LockNode
*)lock
->fl_Key
;
3401 source_name
= source
->ln_FullName
;
3402 source_mode
= source
->ln_FileLock
.fl_Access
;
3406 source_name
= SMB_ROOT_DIR_NAME
;
3407 source_mode
= SHARED_LOCK
;
3410 full_name_size
= strlen(source_name
)+3;
3411 if(full_name_size
< SMB_MAXNAMELEN
+1)
3412 full_name_size
= SMB_MAXNAMELEN
+1;
3414 full_name
= AllocateMemory(full_name_size
);
3415 if(full_name
== NULL
)
3417 error
= ERROR_NO_FREE_STORE
;
3421 strcpy(full_name
,source_name
);
3423 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
3424 ln
->ln_FileLock
.fl_Access
= source_mode
;
3425 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
3426 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
3427 ln
->ln_FullName
= full_name
;
3429 SHOWSTRING(full_name
);
3431 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
3434 error
= MapErrnoToIoErr(error
);
3438 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
3439 result
= MKBADDR(&ln
->ln_FileLock
);
3440 SHOWVALUE(&ln
->ln_FileLock
);
3446 FreeMemory(full_name
);
3450 (*error_ptr
) = error
;
3456 /****************************************************************************/
3460 struct FileLock
* lock
,
3463 LONG result
= DOSTRUE
;
3464 struct LockNode
* ln
;
3474 ln
= (struct LockNode
*)lock
->fl_Key
;
3476 Remove((struct Node
*)ln
);
3477 smba_close(ln
->ln_File
);
3478 FreeMemory(ln
->ln_FullName
);
3483 (*error_ptr
) = error
;
3489 /****************************************************************************/
3493 struct FileLock
* lock1
,
3494 struct FileLock
* lock2
,
3497 LONG result
= DOSFALSE
;
3509 struct LockNode
* ln
= (struct LockNode
*)lock1
->fl_Key
;
3511 name1
= ln
->ln_FullName
;
3515 name1
= SMB_ROOT_DIR_NAME
;
3520 struct LockNode
* ln
= (struct LockNode
*)lock2
->fl_Key
;
3522 name2
= ln
->ln_FullName
;
3526 name2
= SMB_ROOT_DIR_NAME
;
3532 if(Stricmp(name1
,name2
) == SAME
)
3535 (*error_ptr
) = error
;
3541 /****************************************************************************/
3545 struct FileLock
* parent
,
3550 LONG result
= DOSFALSE
;
3551 STRPTR full_name
= NULL
;
3552 LONG full_name_size
;
3553 smba_file_t
* file
= NULL
;
3555 UBYTE name
[MAX_FILENAME_LEN
];
3563 error
= ERROR_DISK_WRITE_PROTECTED
;
3571 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
3573 parent_name
= ln
->ln_FullName
;
3580 ConvertBString(sizeof(name
),name
,bcpl_name
);
3581 TranslateCName(name
,A2M
);
3583 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3587 /* Trying to change the protection bits of the root
3588 * directory, are you kidding?
3590 if(full_name
== NULL
)
3592 error
= ERROR_OBJECT_WRONG_TYPE
;
3596 SHOWSTRING(full_name
);
3598 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
3601 error
= MapErrnoToIoErr(error
);
3605 memset(&st
,0,sizeof(st
));
3607 mask
^= FIBF_READ
| FIBF_WRITE
| FIBF_EXECUTE
| FIBF_DELETE
;
3614 if((mask
& (FIBF_WRITE
|FIBF_DELETE
)) != (FIBF_WRITE
|FIBF_DELETE
))
3616 SHOWMSG("write protection enabled");
3621 SHOWMSG("write protection disabled");
3624 /* Careful: the 'archive' attribute has exactly the opposite
3625 * meaning in the Amiga and the SMB worlds.
3627 st
.is_archive
= ((mask
& FIBF_ARCHIVE
) == 0);
3629 /* The 'system' attribute is associated with the 'pure' bit for now. */
3630 st
.is_system
= ((mask
& FIBF_PURE
) != 0);
3632 error
= smba_setattr(file
,&st
);
3635 error
= MapErrnoToIoErr(error
);
3643 FreeMemory(full_name
);
3647 (*error_ptr
) = error
;
3653 /****************************************************************************/
3656 Action_RenameObject(
3657 struct FileLock
* source_lock
,
3658 APTR source_bcpl_name
,
3659 struct FileLock
* destination_lock
,
3660 APTR destination_bcpl_name
,
3663 struct LockNode
* ln
;
3664 LONG result
= DOSFALSE
;
3665 STRPTR full_source_name
= NULL
;
3666 LONG full_source_name_size
;
3667 STRPTR full_destination_name
= NULL
;
3668 LONG full_destination_name_size
;
3669 UBYTE name
[MAX_FILENAME_LEN
];
3677 error
= ERROR_DISK_WRITE_PROTECTED
;
3681 SHOWVALUE(source_lock
);
3682 SHOWVALUE(destination_lock
);
3684 if(source_lock
!= NULL
)
3686 ln
= (struct LockNode
*)source_lock
->fl_Key
;
3688 parent_name
= ln
->ln_FullName
;
3695 ConvertBString(sizeof(name
),name
,source_bcpl_name
);
3696 TranslateCName(name
,A2M
);
3698 error
= BuildFullName(parent_name
,name
,&full_source_name
,&full_source_name_size
);
3702 /* Trying to rename the root directory, are you kidding? */
3703 if(full_source_name
== NULL
)
3705 error
= ERROR_OBJECT_IN_USE
;
3709 if(destination_lock
!= NULL
)
3711 ln
= (struct LockNode
*)destination_lock
->fl_Key
;
3713 parent_name
= ln
->ln_FullName
;
3720 ConvertBString(sizeof(name
),name
,destination_bcpl_name
);
3721 TranslateCName(name
,A2M
);
3723 error
= BuildFullName(parent_name
,name
,&full_destination_name
,&full_destination_name_size
);
3727 /* Trying to rename the root directory, are you kidding? */
3728 if(full_destination_name
== NULL
)
3730 error
= ERROR_OBJECT_IN_USE
;
3734 error
= NameAlreadyInUse(full_source_name
);
3738 error
= NameAlreadyInUse(full_destination_name
);
3742 SHOWSTRING(full_source_name
);
3743 SHOWSTRING(full_destination_name
);
3745 error
= smba_rename(ServerData
,full_source_name
,full_destination_name
);
3748 error
= MapErrnoToIoErr(error
);
3756 FreeMemory(full_source_name
);
3757 FreeMemory(full_destination_name
);
3759 (*error_ptr
) = error
;
3765 /****************************************************************************/
3769 struct InfoData
* id
,
3772 LONG result
= DOSTRUE
;
3775 long num_blocks_free
;
3780 memset(id
,0,sizeof(*id
));
3783 id
->id_DiskState
= ID_WRITE_PROTECTED
;
3785 id
->id_DiskState
= ID_VALIDATED
;
3787 error
= smba_statfs(ServerData
,&block_size
,&num_blocks
,&num_blocks_free
);
3790 SHOWMSG("got the disk data");
3791 SHOWVALUE(block_size
);
3792 SHOWVALUE(num_blocks
);
3793 SHOWVALUE(num_blocks_free
);
3798 if(block_size
< 512)
3800 num_blocks
/= (512 / block_size
);
3801 num_blocks_free
/= (512 / block_size
);
3803 else if (block_size
> 512)
3805 num_blocks
*= (block_size
/ 512);
3806 num_blocks_free
*= (block_size
/ 512);
3809 id
->id_NumBlocks
= num_blocks
;
3810 id
->id_NumBlocksUsed
= num_blocks
- num_blocks_free
;
3811 id
->id_BytesPerBlock
= 512;
3812 id
->id_DiskType
= ID_DOS_DISK
;
3813 id
->id_VolumeNode
= MKBADDR(VolumeNode
);
3814 id
->id_InUse
= NOT (IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
));
3816 if(id
->id_NumBlocks
== 0)
3817 id
->id_NumBlocks
= 1;
3819 if(id
->id_NumBlocksUsed
== 0)
3820 id
->id_NumBlocksUsed
= 1;
3824 SHOWMSG("could not get any disk data");
3826 id
->id_NumBlocks
= 1;
3827 id
->id_NumBlocksUsed
= 1;
3828 id
->id_BytesPerBlock
= 512;
3829 id
->id_DiskType
= ID_NO_DISK_PRESENT
;
3831 error
= MapErrnoToIoErr(error
);
3835 SHOWVALUE(id
->id_NumBlocks
);
3836 SHOWVALUE(id
->id_NumBlocksUsed
);
3837 SHOWVALUE(id
->id_BytesPerBlock
);
3838 SHOWVALUE(id
->id_DiskType
);
3839 SHOWVALUE(id
->id_VolumeNode
);
3840 SHOWVALUE(id
->id_InUse
);
3842 (*error_ptr
) = error
;
3850 struct FileLock
* lock
,
3851 struct InfoData
* id
,
3860 if(lock
== NULL
|| lock
->fl_Volume
!= MKBADDR(VolumeNode
))
3862 SHOWMSG("volume node does not match");
3866 (*error_ptr
) = ERROR_NO_DISK
;
3870 result
= Action_DiskInfo(id
,error_ptr
);
3877 /****************************************************************************/
3880 Action_ExamineObject(
3881 struct FileLock
* lock
,
3882 struct FileInfoBlock
* fib
,
3885 LONG result
= DOSFALSE
;
3892 memset(fib
,0,sizeof(*fib
));
3896 #if !defined(__AROS__)
3897 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3898 LONG len
= volume_name
[0];
3900 memcpy(fib
->fib_FileName
+1, volume_name
+ 1, len
);
3901 fib
->fib_FileName
[0] = len
;
3903 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3904 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3906 memcpy(fib
->fib_FileName
, volume_name
, len
);
3908 SHOWMSG("ZERO root lock");
3910 fib
->fib_DirEntryType
= ST_ROOT
;
3911 fib
->fib_EntryType
= ST_ROOT
;
3912 fib
->fib_NumBlocks
= 1;
3913 fib
->fib_Date
= VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
;
3914 fib
->fib_DiskKey
= -1;
3915 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3916 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3920 struct LockNode
* ln
= (struct LockNode
*)lock
->fl_Key
;
3924 error
= smba_getattr(ln
->ln_File
,&st
);
3927 SHOWMSG("information not available");
3929 error
= MapErrnoToIoErr(error
);
3933 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
3937 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
3938 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
3939 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
3941 SHOWSTRING(ln
->ln_FullName
);
3943 if(strcmp(ln
->ln_FullName
,SMB_ROOT_DIR_NAME
) == SAME
)
3945 #if !defined(__AROS__)
3946 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3947 LONG len
= volume_name
[0];
3949 memcpy(fib
->fib_FileName
+1, volume_name
+ 1, len
);
3950 fib
->fib_FileName
[0] = len
;
3952 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3953 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3955 memcpy(fib
->fib_FileName
, volume_name
, len
);
3957 SHOWMSG("root lock");
3959 fib
->fib_DirEntryType
= ST_ROOT
;
3960 fib
->fib_EntryType
= ST_ROOT
;
3961 fib
->fib_NumBlocks
= 1;
3962 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3963 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3970 name
= ln
->ln_FullName
;
3971 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
3973 if(name
[i
] == SMB_PATH_SEPARATOR
)
3980 /* Just checking: will the name fit? */
3981 if(strlen(name
) >= sizeof(fib
->fib_FileName
))
3983 error
= ERROR_INVALID_COMPONENT_NAME
;
3987 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
3988 TranslateBName(fib
->fib_FileName
,M2A
);
3990 fib
->fib_DirEntryType
= st
.is_dir
? ST_USERDIR
: ST_FILE
;
3991 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
3992 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
3993 fib
->fib_Size
= st
.size
;
3994 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3995 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3998 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4000 /* Careful: the 'archive' attribute has exactly the opposite
4001 * meaning in the Amiga and the SMB worlds.
4003 if(NOT st
.is_archive
)
4004 fib
->fib_Protection
|= FIBF_ARCHIVE
;
4007 fib
->fib_Protection
|= FIBF_PURE
;
4010 fib
->fib_DiskKey
= -1;
4016 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib
->fib_FileName
)));
4017 SHOWVALUE(fib
->fib_DirEntryType
);
4018 SHOWVALUE(fib
->fib_NumBlocks
);
4019 SHOWVALUE(fib
->fib_Size
);
4020 SHOWVALUE(fib
->fib_Date
.ds_Days
);
4021 SHOWVALUE(fib
->fib_Date
.ds_Minute
);
4022 SHOWVALUE(fib
->fib_Date
.ds_Tick
);
4023 SHOWVALUE(fib
->fib_DiskKey
);
4027 (*error_ptr
) = error
;
4033 /****************************************************************************/
4036 NameIsAcceptable(STRPTR name
,LONG max_len
)
4038 BOOL result
= FALSE
;
4041 /* This takes care of "." and "..". */
4042 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
4045 /* Now for embedded '/', ':' and '\' characters and
4046 * names that just don't want to fit.
4048 while((c
= (*name
++)) != '\0')
4051 if(max_len
== 0 || c
== '/' || c
== ':' || c
== SMB_PATH_SEPARATOR
)
4062 /****************************************************************************/
4065 dir_scan_callback_func_exnext(
4066 struct FileInfoBlock
* fib
,
4078 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4079 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
4080 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
4082 /* Skip file and drawer names that we wouldn't be
4083 * able to handle in the first place.
4085 if(NameIsAcceptable((STRPTR
)name
,sizeof(fib
->fib_FileName
)) && NOT (st
->is_hidden
&& OmitHidden
))
4089 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
4090 TranslateBName(fib
->fib_FileName
,M2A
);
4092 fib
->fib_DirEntryType
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
4093 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
4094 fib
->fib_NumBlocks
= (st
->size
+ 511) / 512;
4095 fib
->fib_Size
= st
->size
;
4096 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
4097 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
4100 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4102 /* Careful: the 'archive' attribute has exactly the opposite
4103 * meaning in the Amiga and the SMB worlds.
4105 if(NOT st
->is_archive
)
4106 fib
->fib_Protection
|= FIBF_ARCHIVE
;
4109 fib
->fib_Protection
|= FIBF_PURE
;
4111 seconds
= st
->mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
4115 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
4116 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
4117 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
4126 fib
->fib_DiskKey
= eof
? -1 : nextpos
;
4134 struct FileLock
* lock
,
4135 struct FileInfoBlock
* fib
,
4138 struct LockNode
* ln
;
4139 LONG result
= DOSFALSE
;
4148 if(fib
->fib_DiskKey
== -1)
4150 SHOWMSG("scanning finished.");
4151 error
= ERROR_NO_MORE_ENTRIES
;
4157 SHOWMSG("invalid lock");
4158 error
= ERROR_INVALID_LOCK
;
4162 offset
= fib
->fib_DiskKey
;
4164 ln
= (struct LockNode
*)lock
->fl_Key
;
4166 /* Check if we should restart scanning the directory
4167 * contents. This is tricky at best and may produce
4168 * irritating results :(
4170 if(ln
->ln_RestartExamine
)
4174 ln
->ln_RestartExamine
= FALSE
;
4177 memset(fib
,0,sizeof(*fib
));
4179 SHOWMSG("calling 'smba_readdir'");
4182 count
= smba_readdir(ln
->ln_File
,offset
,fib
,(smba_callback_t
)dir_scan_callback_func_exnext
);
4186 if(count
== 0 || fib
->fib_FileName
[0] == '\0')
4188 SHOWMSG("nothing to be read");
4189 fib
->fib_DiskKey
= -1;
4191 error
= ERROR_NO_MORE_ENTRIES
;
4194 else if (count
== (-EIO
))
4196 SHOWMSG("ouch! directory read error");
4197 fib
->fib_DiskKey
= -1;
4199 error
= ERROR_NO_DEFAULT_DIR
;
4204 SHOWMSG("error whilst scanning");
4206 fib
->fib_DiskKey
= -1;
4208 error
= MapErrnoToIoErr(count
);
4216 (*error_ptr
) = error
;
4222 /****************************************************************************/
4226 struct ExAllData
* ec_Last
;
4227 struct ExAllData
* ec_Next
;
4230 struct ExAllControl
* ec_Control
;
4233 BOOL ec_FirstAttempt
;
4237 dir_scan_callback_func_exall(
4238 struct ExAllContext
* ec
,
4250 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
4251 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
4252 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
4254 /* Skip file and drawer names that we wouldn't be
4255 * able to handle in the first place.
4257 if(NameIsAcceptable((STRPTR
)name
,MAX_FILENAME_LEN
) && NOT (st
->is_hidden
&& OmitHidden
))
4259 struct ExAllData
* ed
;
4261 ULONG type
= ec
->ec_Type
;
4264 size
= (ec
->ec_MinSize
+ strlen(name
)+1 + 3) & ~3UL;
4266 if(size
> ec
->ec_BytesLeft
)
4268 D(("size %ld > ec->ec_BytesLeft %ld",size
,ec
->ec_BytesLeft
));
4270 /* If this is the first directory entry,
4271 * stop the entire process before it has
4274 if(ec
->ec_FirstAttempt
)
4276 SHOWMSG("this was the first read attempt.");
4277 ec
->ec_Control
->eac_Entries
= 0;
4278 ec
->ec_Error
= ERROR_NO_FREE_STORE
;
4282 SHOWMSG("try again");
4293 ed
->ed_Name
= (STRPTR
)(((IPTR
)ed
) + ec
->ec_MinSize
);
4294 strcpy(ed
->ed_Name
,name
);
4296 TranslateCName(ed
->ed_Name
,M2A
);
4299 ed
->ed_Type
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
4302 ed
->ed_Size
= st
->size
;
4304 if(type
>= ED_PROTECTION
)
4306 ed
->ed_Prot
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
4307 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
4310 ed
->ed_Prot
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4312 /* Careful: the 'archive' attribute has exactly the opposite
4313 * meaning in the Amiga and the SMB worlds.
4315 if(NOT st
->is_archive
)
4316 ed
->ed_Prot
|= FIBF_ARCHIVE
;
4319 ed
->ed_Prot
|= FIBF_PURE
;
4326 seconds
= st
->mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
4330 ed
->ed_Days
= (seconds
/ (24 * 60 * 60));
4331 ed
->ed_Mins
= (seconds
% (24 * 60 * 60)) / 60;
4332 ed
->ed_Ticks
= (seconds
% 60) * TICKS_PER_SECOND
;
4335 if(type
>= ED_COMMENT
)
4336 ed
->ed_Comment
= "";
4338 if(type
>= ED_OWNER
)
4339 ed
->ed_OwnerUID
= ed
->ed_OwnerGID
= 0;
4343 if(ec
->ec_Control
->eac_MatchString
!= NULL
)
4345 SHOWMSG("checking against match string");
4346 if(NOT
MatchPatternNoCase(ec
->ec_Control
->eac_MatchString
,ed
->ed_Name
))
4348 SHOWMSG("does not match");
4353 if(take_it
&& ec
->ec_Control
->eac_MatchFunc
!= NULL
)
4355 SHOWMSG("calling match func");
4357 /* NOTE: the order of the parameters passed to the match hook
4358 * function can be somewhat confusing. For standard
4359 * hook functions, the order of the parameters and the
4360 * registers they go into is hook=A0, object=A2,
4361 * message=A1. However, the documentation for the 'ExAll()'
4362 * function always lists them in ascending order, that is
4363 * hook=A0, message=A1, object=A2, which can lead to
4364 * quite some confusion and strange errors.
4366 if(NOT
CallHookPkt(ec
->ec_Control
->eac_MatchFunc
,&type
,ed
))
4368 SHOWMSG("does not match");
4375 SHOWMSG("registering new entry");
4377 if(ec
->ec_Last
!= NULL
)
4378 ec
->ec_Last
->ed_Next
= ed
;
4381 ec
->ec_Next
= (struct ExAllData
*)(((IPTR
)ed
) + size
);
4382 ec
->ec_BytesLeft
-= size
;
4383 ec
->ec_Control
->eac_Entries
++;
4385 SHOWVALUE(ec
->ec_Last
->ed_Next
);
4386 SHOWVALUE(ed
->ed_Name
);
4387 SHOWVALUE(ed
->ed_Comment
);
4391 ec
->ec_Control
->eac_LastKey
= (ULONG
)(eof
? -1 : nextpos
);
4395 ec
->ec_FirstAttempt
= FALSE
;
4403 struct FileLock
* lock
,
4404 struct ExAllData
* ed
,
4407 struct ExAllControl
* eac
,
4410 struct ExAllContext ec
;
4411 struct LockNode
* ln
;
4412 LONG result
= DOSFALSE
;
4421 SHOWVALUE(eac
->eac_LastKey
);
4423 eac
->eac_Entries
= 0;
4425 if(size
< sizeof(ed
->ed_Next
))
4427 SHOWMSG("buffer is far too short.");
4428 error
= ERROR_NO_FREE_STORE
;
4434 if(eac
->eac_LastKey
== (ULONG
)-1)
4436 SHOWMSG("scanning finished.");
4437 error
= ERROR_NO_MORE_ENTRIES
;
4443 SHOWMSG("invalid lock");
4444 error
= ERROR_INVALID_LOCK
;
4448 if(type
< ED_NAME
|| type
> ED_OWNER
)
4450 D(("type %ld not supported",type
));
4451 error
= ERROR_BAD_NUMBER
;
4457 memset(&ec
,0,sizeof(ec
));
4460 ec
.ec_BytesLeft
= size
;
4461 ec
.ec_Control
= eac
;
4463 ec
.ec_Error
= ERROR_NO_MORE_ENTRIES
;
4464 ec
.ec_FirstAttempt
= TRUE
;
4470 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Type
);
4475 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Size
);
4480 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Prot
);
4485 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Days
);
4490 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Comment
);
4495 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_OwnerUID
);
4500 ec
.ec_MinSize
= sizeof(struct ExAllData
);
4504 SHOWVALUE(ec
.ec_MinSize
);
4506 offset
= eac
->eac_LastKey
;
4508 ln
= (struct LockNode
*)lock
->fl_Key
;
4510 /* Check if we should restart scanning the directory
4511 * contents. This is tricky at best and may produce
4512 * irritating results :(
4514 if(ln
->ln_RestartExamine
)
4518 ln
->ln_RestartExamine
= FALSE
;
4525 SHOWMSG("first invocation");
4527 SHOWMSG("getting file attributes");
4528 error
= smba_getattr(ln
->ln_File
,&st
);
4531 SHOWMSG("didn't work");
4532 error
= MapErrnoToIoErr(error
);
4533 eac
->eac_LastKey
= (ULONG
)-1;
4539 SHOWMSG("lock does not refer to a directory");
4540 error
= ERROR_OBJECT_WRONG_TYPE
;
4541 eac
->eac_LastKey
= (ULONG
)-1;
4546 SHOWMSG("calling 'smba_readdir'");
4549 count
= smba_readdir(ln
->ln_File
,offset
,&ec
,(smba_callback_t
)dir_scan_callback_func_exall
);
4553 if(count
== 0 || eac
->eac_Entries
== 0)
4555 SHOWMSG("nothing to be read");
4556 if(ec
.ec_Error
!= OK
)
4558 SHOWMSG("flagging an error");
4559 SHOWVALUE(ec
.ec_Error
);
4560 eac
->eac_LastKey
= (ULONG
)-1;
4561 error
= ec
.ec_Error
;
4566 else if (count
== (-EIO
))
4568 SHOWMSG("ouch! directory read error");
4569 eac
->eac_LastKey
= (ULONG
)-1;
4571 error
= ERROR_NO_DEFAULT_DIR
;
4576 SHOWMSG("error whilst scanning");
4577 eac
->eac_LastKey
= (ULONG
)-1;
4579 error
= MapErrnoToIoErr(count
);
4590 SHOWVALUE(eac
->eac_Entries
);
4594 SHOWSTRING(ed
->ed_Name
);
4601 (*error_ptr
) = error
;
4607 /****************************************************************************/
4612 struct FileHandle
* fh
,
4613 struct FileLock
* parent
,
4617 LONG result
= DOSFALSE
;
4618 STRPTR parent_path
= NULL
;
4619 STRPTR full_name
= NULL
;
4620 LONG full_name_size
;
4621 struct FileNode
* fn
= NULL
;
4623 UBYTE name
[MAX_FILENAME_LEN
];
4624 BOOL create_new_file
;
4631 case ACTION_FINDINPUT
:
4632 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name
)));
4635 case ACTION_FINDOUTPUT
:
4636 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name
)));
4639 case ACTION_FINDUPDATE
:
4640 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name
)));
4648 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
4650 parent_name
= ln
->ln_FullName
;
4657 ConvertBString(sizeof(name
),name
,bcpl_name
);
4658 TranslateCName(name
,A2M
);
4660 if(IsReservedName(FilePart(name
)))
4662 error
= ERROR_OBJECT_NOT_FOUND
;
4666 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
4670 /* Trying to open the root directory? */
4671 if(full_name
== NULL
)
4673 error
= ERROR_OBJECT_WRONG_TYPE
;
4677 fn
= AllocateMemory(sizeof(*fn
));
4680 error
= ERROR_NO_FREE_STORE
;
4684 memset(fn
,0,sizeof(*fn
));
4687 fn
->fn_FullName
= full_name
;
4688 fn
->fn_Mode
= (action
== ACTION_FINDOUTPUT
) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
4690 error
= CheckAccessModeCollision(full_name
,fn
->fn_Mode
);
4694 SHOWSTRING(full_name
);
4696 if(action
== ACTION_FINDOUTPUT
)
4698 /* Definitely create a new file. */
4699 create_new_file
= TRUE
;
4701 else if (action
== ACTION_FINDINPUT
)
4703 /* Open an existing file for reading. */
4704 create_new_file
= FALSE
;
4706 else if (action
== ACTION_FINDUPDATE
)
4708 smba_file_t
* file
= NULL
;
4711 if(smba_open(ServerData
,full_name
,full_name_size
,&file
) == OK
&&
4712 smba_getattr(file
,&st
) == OK
)
4714 /* File apparently opens Ok and information on it
4715 * is available, don't try to replace it.
4717 create_new_file
= FALSE
;
4721 /* We try to ignore the error here and assume
4722 * that the remainder of the file opening
4723 * procedure will produce a useful error
4724 * report. In the mean time, assume that the
4725 * file needs to be created.
4727 create_new_file
= TRUE
;
4736 error
= ERROR_ACTION_NOT_KNOWN
;
4740 /* Create a new file? */
4750 error
= ERROR_DISK_WRITE_PROTECTED
;
4754 parent_path
= AllocateMemory(strlen(full_name
)+3);
4755 if(parent_path
== NULL
)
4757 error
= ERROR_NO_FREE_STORE
;
4761 strcpy(parent_path
,full_name
);
4763 for(i
= strlen(parent_path
)-1 ; i
>= 0 ; i
--)
4765 if(parent_path
[i
] == SMB_PATH_SEPARATOR
)
4769 memmove(&parent_path
[1],&parent_path
[0],strlen(parent_path
)+1);
4773 parent_path
[i
] = '\0';
4775 base_name
= &parent_path
[i
+1];
4780 SHOWMSG("creating a file; finding parent path first");
4781 SHOWSTRING(parent_path
);
4783 error
= smba_open(ServerData
,parent_path
,strlen(full_name
)+3,&dir
);
4786 error
= MapErrnoToIoErr(error
);
4790 /* Only one attribute counts: the file should not be write protected. */
4791 memset(&st
,0,sizeof(st
));
4793 SHOWMSG("now trying to create the file");
4794 SHOWSTRING(base_name
);
4796 error
= smba_create(dir
,base_name
,&st
);
4799 SHOWMSG("didn't work.");
4803 error
= MapErrnoToIoErr(error
);
4815 /* Now for the remainder... */
4816 error
= smba_open(ServerData
,full_name
,full_name_size
,&fn
->fn_File
);
4819 error
= MapErrnoToIoErr(error
);
4823 fh
->fh_Arg1
= (IPTR
)fn
;
4825 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
4830 if(result
== DOSFALSE
)
4832 FreeMemory(full_name
);
4836 FreeMemory(parent_path
);
4838 (*error_ptr
) = error
;
4844 /****************************************************************************/
4848 struct FileNode
* fn
,
4860 result
= smba_read(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4863 error
= MapErrnoToIoErr(result
);
4868 fn
->fn_Offset
+= result
;
4873 (*error_ptr
) = error
;
4879 /****************************************************************************/
4883 struct FileNode
* fn
,
4888 LONG result
= DOSFALSE
;
4895 error
= ERROR_DISK_WRITE_PROTECTED
;
4901 result
= smba_write(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4904 error
= MapErrnoToIoErr(result
);
4909 fn
->fn_Offset
+= result
;
4914 (*error_ptr
) = error
;
4920 /****************************************************************************/
4924 struct FileNode
* fn
,
4927 Remove((struct Node
*)fn
);
4929 smba_close(fn
->fn_File
);
4930 FreeMemory(fn
->fn_FullName
);
4937 /****************************************************************************/
4941 struct FileNode
* fn
,
4946 LONG previous_position
= fn
->fn_Offset
;
4953 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4958 case OFFSET_BEGINNING
:
4963 case OFFSET_CURRENT
:
4975 error
= ERROR_ACTION_NOT_KNOWN
;
4979 error
= smba_seek (fn
->fn_File
, position
, mode
, (off_t
*) &offset
);
4982 error
= MapErrnoToIoErr(error
);
4988 /* olsen: This is the original implementation. */
4993 error
= smba_getattr(fn
->fn_File
,&st
);
4996 error
= MapErrnoToIoErr(error
);
5000 offset
= fn
->fn_Offset
;
5004 case OFFSET_BEGINNING
:
5009 case OFFSET_CURRENT
:
5016 offset
= st
.size
+ position
;
5021 error
= ERROR_ACTION_NOT_KNOWN
;
5025 if(offset
< 0 || offset
> st
.size
)
5027 error
= ERROR_SEEK_ERROR
;
5033 /* olsen: This is a mix of the two above. First we calculate the absolute
5034 * position, then seek to that position. The SMB server is supposed
5035 * to do its housekeeping before the position is changed. I wish this
5036 * worked differently, but it seems we've got the best of both worlds
5045 case OFFSET_BEGINNING
:
5050 case OFFSET_CURRENT
:
5052 offset
= fn
->fn_Offset
+ position
;
5057 error
= smba_getattr(fn
->fn_File
,&st
);
5060 error
= MapErrnoToIoErr(error
);
5064 offset
= st
.size
+ position
;
5069 error
= ERROR_ACTION_NOT_KNOWN
;
5075 error
= ERROR_SEEK_ERROR
;
5079 error
= smba_seek (fn
->fn_File
, offset
, 0, (off_t
*) &offset
);
5082 error
= MapErrnoToIoErr(error
);
5090 fn
->fn_Offset
= offset
;
5092 result
= previous_position
;
5096 (*error_ptr
) = error
;
5102 /****************************************************************************/
5106 struct FileNode
* fn
,
5120 error
= ERROR_DISK_WRITE_PROTECTED
;
5124 error
= smba_getattr(fn
->fn_File
,&st
);
5127 error
= MapErrnoToIoErr(error
);
5131 offset
= fn
->fn_Offset
;
5135 case OFFSET_BEGINNING
:
5140 case OFFSET_CURRENT
:
5147 offset
= st
.size
+ position
;
5152 error
= ERROR_ACTION_NOT_KNOWN
;
5158 error
= ERROR_SEEK_ERROR
;
5167 error
= smba_setattr(fn
->fn_File
,&st
);
5170 error
= MapErrnoToIoErr(error
);
5174 if(fn
->fn_Offset
> offset
)
5175 fn
->fn_Offset
= offset
;
5181 (*error_ptr
) = error
;
5187 /****************************************************************************/
5191 struct FileLock
* parent
,
5193 struct DateStamp
* ds
,
5196 LONG result
= DOSFALSE
;
5197 STRPTR full_name
= NULL
;
5198 LONG full_name_size
;
5199 smba_file_t
* file
= NULL
;
5201 UBYTE name
[MAX_FILENAME_LEN
];
5210 error
= ERROR_DISK_WRITE_PROTECTED
;
5218 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5220 parent_name
= ln
->ln_FullName
;
5227 ConvertBString(sizeof(name
),name
,bcpl_name
);
5228 TranslateCName(name
,A2M
);
5230 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
5234 /* Trying to change the date of the root directory? */
5235 if(full_name
== NULL
)
5237 error
= ERROR_OBJECT_IN_USE
;
5241 SHOWSTRING(full_name
);
5243 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5246 error
= MapErrnoToIoErr(error
);
5250 error
= smba_getattr(file
,&st
);
5253 error
= MapErrnoToIoErr(error
);
5257 seconds
= (ds
->ds_Days
* 24 * 60 + ds
->ds_Minute
) * 60 + (ds
->ds_Tick
/ TICKS_PER_SECOND
);
5261 st
.mtime
= seconds
+ UNIX_TIME_OFFSET
+ GetTimeZoneDelta();
5264 error
= smba_setattr(file
,&st
);
5267 error
= MapErrnoToIoErr(error
);
5275 FreeMemory(full_name
);
5279 (*error_ptr
) = error
;
5285 /****************************************************************************/
5289 struct FileNode
* fn
,
5290 struct FileInfoBlock
* fib
,
5293 LONG result
= DOSFALSE
;
5302 error
= smba_getattr(fn
->fn_File
,&st
);
5305 error
= MapErrnoToIoErr(error
);
5309 name
= fn
->fn_FullName
;
5310 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
5312 if(name
[i
] == SMB_PATH_SEPARATOR
)
5319 /* Just checking: will the name fit? */
5320 if(strlen(name
) >= sizeof(fib
->fib_FileName
))
5322 error
= ERROR_INVALID_COMPONENT_NAME
;
5326 memset(fib
,0,sizeof(*fib
));
5328 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
5329 TranslateBName(fib
->fib_FileName
,M2A
);
5331 fib
->fib_DirEntryType
= ST_FILE
;
5332 fib
->fib_EntryType
= ST_FILE
;
5333 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
5334 fib
->fib_Size
= st
.size
;
5335 fib
->fib_DiskKey
= -1;
5337 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
5338 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
5341 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
5343 /* Careful: the 'archive' attribute has exactly the opposite
5344 * meaning in the Amiga and the SMB worlds.
5346 if(NOT st
.is_archive
)
5347 fib
->fib_Protection
|= FIBF_ARCHIVE
;
5350 fib
->fib_Protection
|= FIBF_PURE
;
5352 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
5356 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
5357 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
5358 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
5364 (*error_ptr
) = error
;
5370 /****************************************************************************/
5374 struct FileNode
* fn
,
5378 struct LockNode
* ln
= NULL
;
5381 LONG full_name_size
;
5386 full_name_size
= strlen(fn
->fn_FullName
)+3;
5387 if(full_name_size
< SMB_MAXNAMELEN
+1)
5388 full_name_size
= SMB_MAXNAMELEN
+1;
5390 full_name
= AllocateMemory(full_name_size
);
5391 if(full_name
== NULL
)
5393 error
= ERROR_NO_FREE_STORE
;
5397 strcpy(full_name
,fn
->fn_FullName
);
5399 for(i
= strlen(full_name
)-1 ; i
>= 0 ; i
--)
5403 strcpy(full_name
,SMB_ROOT_DIR_NAME
);
5406 else if (full_name
[i
] == SMB_PATH_SEPARATOR
)
5408 full_name
[i
] = '\0';
5413 ln
= AllocateMemory(sizeof(*ln
));
5416 error
= ERROR_NO_FREE_STORE
;
5420 memset(ln
,0,sizeof(*ln
));
5422 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
5423 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
5424 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
5425 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
5426 ln
->ln_FullName
= full_name
;
5428 SHOWSTRING(full_name
);
5430 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
5433 error
= MapErrnoToIoErr(error
);
5437 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5438 result
= MKBADDR(&ln
->ln_FileLock
);
5439 SHOWVALUE(&ln
->ln_FileLock
);
5446 FreeMemory(full_name
);
5449 (*error_ptr
) = error
;
5455 /****************************************************************************/
5459 struct FileNode
* fn
,
5463 struct LockNode
* ln
= NULL
;
5464 STRPTR full_name
= NULL
;
5465 LONG full_name_size
;
5470 if(fn
->fn_Mode
!= SHARED_LOCK
)
5472 error
= ERROR_OBJECT_IN_USE
;
5476 full_name_size
= strlen(fn
->fn_FullName
)+3;
5477 if(full_name_size
< SMB_MAXNAMELEN
+1)
5478 full_name_size
= SMB_MAXNAMELEN
+1;
5480 full_name
= AllocateMemory(full_name_size
);
5481 if(full_name
== NULL
)
5483 error
= ERROR_NO_FREE_STORE
;
5487 strcpy(full_name
,fn
->fn_FullName
);
5489 ln
= AllocateMemory(sizeof(*ln
));
5492 error
= ERROR_NO_FREE_STORE
;
5496 memset(ln
,0,sizeof(*ln
));
5498 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
5499 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
5500 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
5501 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
5502 ln
->ln_FullName
= full_name
;
5504 SHOWSTRING(full_name
);
5506 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
5509 error
= MapErrnoToIoErr(error
);
5513 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
5514 result
= MKBADDR(&ln
->ln_FileLock
);
5515 SHOWVALUE(&ln
->ln_FileLock
);
5522 FreeMemory(full_name
);
5525 (*error_ptr
) = error
;
5531 /****************************************************************************/
5535 struct FileHandle
* fh
,
5536 struct FileLock
* fl
,
5539 LONG result
= DOSFALSE
;
5540 struct FileNode
* fn
;
5541 struct LockNode
* ln
;
5548 fn
= AllocateMemory(sizeof(*fn
));
5551 error
= ERROR_NO_FREE_STORE
;
5555 memset(fn
,0,sizeof(*fn
));
5557 ln
= (struct LockNode
*)fl
->fl_Key
;
5560 fn
->fn_FullName
= ln
->ln_FullName
;
5561 fn
->fn_File
= ln
->ln_File
;
5562 fn
->fn_Mode
= fl
->fl_Access
;
5564 Remove((struct Node
*)ln
);
5567 fh
->fh_Arg1
= (IPTR
)fn
;
5569 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
5574 (*error_ptr
) = error
;
5580 /****************************************************************************/
5587 LONG result
= DOSFALSE
;
5596 if(NOT VolumeNodeAdded
)
5598 error
= ERROR_OBJECT_IN_USE
;
5604 error
= ERROR_DISK_WRITE_PROTECTED
;
5608 /* Now for the really interesting part; the new name
5609 * is to be a NUL-terminated BCPL string, and as such
5610 * must be allocated via AllocVec().
5617 new_name
= AllocVec(1 + len
+ 1,MEMF_ANY
|MEMF_PUBLIC
);
5618 if(new_name
== NULL
)
5620 error
= ERROR_NO_FREE_STORE
;
5625 memcpy(&new_name
[1],&name
[1],len
);
5626 new_name
[len
+1] = '\0';
5630 old_name
= BADDR(VolumeNode
->dol_Name
);
5631 VolumeNode
->dol_Name
= MKBADDR(new_name
);
5637 SendDiskChange(IECLASS_DISKINSERTED
);
5643 (*error_ptr
) = error
;
5649 /****************************************************************************/
5658 LONG result
= DOSFALSE
;
5659 struct FileLock
* fl
= NULL
;
5660 struct FileNode
* fn
= NULL
;
5661 struct LockNode
* ln
= NULL
;
5668 /* Sanity check; verify parameters */
5669 if((type
!= CHANGE_LOCK
&& type
!= CHANGE_FH
) ||
5670 (new_mode
!= EXCLUSIVE_LOCK
&& new_mode
!= SHARED_LOCK
))
5672 error
= ERROR_ACTION_NOT_KNOWN
;
5676 /* Now obtain the data structures, name and mode
5677 * associated with the object in question.
5679 if(type
== CHANGE_LOCK
)
5682 ln
= (struct LockNode
*)fl
->fl_Key
;
5683 name
= ln
->ln_FullName
;
5684 old_mode
= fl
->fl_Access
;
5688 struct FileHandle
* fh
= object
;
5690 fn
= (struct FileNode
*)fh
->fh_Arg1
;
5691 name
= fn
->fn_FullName
;
5692 old_mode
= fn
->fn_Mode
;
5695 /* Do we need to change anything at all? */
5696 if(new_mode
== old_mode
)
5702 /* This is the easiest case; change an
5703 * exclusive access mode to a shared
5704 * access mode. Since the original mode
5705 * can be used by one object only,
5706 * we get away by updating the mode
5709 if(new_mode
== SHARED_LOCK
)
5711 if(type
== CHANGE_LOCK
)
5712 fl
->fl_Access
= new_mode
;
5714 fn
->fn_Mode
= new_mode
;
5720 /* Is there another shared access lock
5721 * which refers to the same object?
5723 if(FindLockNode(name
,ln
) != NULL
)
5725 error
= ERROR_OBJECT_IN_USE
;
5729 /* Is there another shared access file
5730 * which refers to the same object?
5732 if(FindFileNode(name
,fn
) != NULL
)
5734 error
= ERROR_OBJECT_IN_USE
;
5738 /* There is just one single reference
5739 * to this object; change the mode
5742 if(type
== CHANGE_LOCK
)
5743 fl
->fl_Access
= new_mode
;
5745 fn
->fn_Mode
= new_mode
;
5751 (*error_ptr
) = error
;
5757 /****************************************************************************/
5760 Action_WriteProtect(
5765 LONG result
= DOSFALSE
;
5770 if(flag
== DOSFALSE
)
5774 if(key
!= WriteProtectKey
)
5776 error
= ERROR_INVALID_LOCK
;
5780 WriteProtected
= FALSE
;
5784 SendDiskChange(IECLASS_DISKREMOVED
);
5785 SendDiskChange(IECLASS_DISKINSERTED
);
5791 if(NOT WriteProtected
)
5793 WriteProtected
= TRUE
;
5794 WriteProtectKey
= key
;
5798 SendDiskChange(IECLASS_DISKREMOVED
);
5799 SendDiskChange(IECLASS_DISKINSERTED
);
5804 error
= ERROR_INVALID_LOCK
;
5813 (*error_ptr
) = error
;
5819 /****************************************************************************/
5831 old_size
= smba_get_dircache_size(ServerData
);
5833 result
= smba_change_dircache_size(ServerData
,old_size
+ buffer_delta
);
5835 if(result
== old_size
&& buffer_delta
!= 0)
5838 (*error_ptr
) = ERROR_NO_FREE_STORE
;
5845 /****************************************************************************/
5849 struct FileLock
* parent
,
5854 LONG result
= DOSFALSE
;
5855 STRPTR full_name
= NULL
;
5856 LONG full_name_size
;
5857 smba_file_t
* file
= NULL
;
5859 UBYTE name
[MAX_FILENAME_LEN
];
5867 error
= ERROR_DISK_WRITE_PROTECTED
;
5875 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5877 parent_name
= ln
->ln_FullName
;
5884 ConvertBString(sizeof(name
),name
,bcpl_name
);
5885 TranslateCName(name
,A2M
);
5887 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
5891 /* Trying to change the comment of the root directory? */
5892 if(full_name
== NULL
)
5894 error
= ERROR_OBJECT_IN_USE
;
5898 SHOWSTRING(full_name
);
5900 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5903 error
= MapErrnoToIoErr(error
);
5907 ConvertBString(sizeof(comment
),comment
,bcpl_comment
);
5909 SHOWSTRING(comment
);
5911 /* All this work and we're only doing something very silly... */
5912 if(strlen(comment
) > 0)
5914 error
= ERROR_COMMENT_TOO_BIG
;
5922 FreeMemory(full_name
);
5926 (*error_ptr
) = error
;
5932 /****************************************************************************/
5936 struct FileNode
* fn
,
5943 LONG result
= DOSFALSE
;
5947 /* Sanity checks... */
5948 if (mode
< REC_EXCLUSIVE
|| mode
> REC_SHARED_IMMED
)
5950 error
= ERROR_ACTION_NOT_KNOWN
;
5954 /* Invalid offset, size or integer overflow? */
5955 if (offset
< 0 || length
<= 0 || offset
+ length
< offset
)
5957 error
= ERROR_LOCK_COLLISION
;
5961 if ((mode
== REC_SHARED
) || (mode
== REC_SHARED_IMMED
))
5966 if ((mode
== REC_SHARED_IMMED
) || (mode
== REC_EXCLUSIVE_IMMED
))
5971 if (timeout
> 214748364)
5972 timeout
= ~0; /* wait forever */
5974 timeout
*= 20; /* milliseconds instead of Ticks */
5977 error
= smba_lockrec (fn
->fn_File
, offset
, length
, umode
, 0, (long)timeout
);
5980 error
= MapErrnoToIoErr(error
);
5988 (*error_ptr
) = error
;
5994 /****************************************************************************/
5998 struct FileNode
* fn
,
6003 LONG result
= DOSFALSE
;
6006 /* Sanity checks... */
6007 if(offset
< 0 || length
<= 0 || offset
+ length
< offset
)
6009 error
= ERROR_RECORD_NOT_LOCKED
;
6013 error
= smba_lockrec (fn
->fn_File
, offset
, length
, 2, -1, 0);
6016 error
= MapErrnoToIoErr(error
);
6024 (*error_ptr
) = error
;
6030 /****************************************************************************/
6033 HandleFileSystem(STRPTR device_name
,STRPTR volume_name
,STRPTR service_name
)
6035 BOOL sign_off
= FALSE
;
6043 if(NOT Quiet
&& WBStartup
== NULL
)
6045 struct CommandLineInterface
* cli
;
6048 if(NOT cli
->cli_Background
)
6050 struct Process
* this_process
;
6051 UBYTE name
[MAX_FILENAME_LEN
];
6056 this_process
= (struct Process
*)FindTask(NULL
);
6060 which
= max_cli
= MaxCli();
6062 for(i
= 1 ; i
<= max_cli
; i
++)
6064 if(FindCliProc(i
) == this_process
)
6073 if(volume_name
== NULL
)
6074 strlcpy(name
,device_name
,sizeof(name
));
6076 strlcpy(name
,volume_name
,sizeof(name
));
6078 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
6086 LocalPrintf("Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ",
6087 service_name
,name
,which
);
6101 signals
= Wait(SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_F
| (1UL << FileSystemPort
->mp_SigBit
));
6103 if(signals
& (1UL << FileSystemPort
->mp_SigBit
))
6105 struct DosPacket
* dp
;
6106 struct Message
* mn
;
6109 while((mn
= GetMsg(FileSystemPort
)) != NULL
)
6111 dp
= (struct DosPacket
*)mn
->mn_Node
.ln_Name
;
6113 D(("got packet; sender '%s'",((struct Node
*)dp
->dp_Port
->mp_SigTask
)->ln_Name
));
6117 switch(dp
->dp_Action
)
6121 SHOWMSG("ACTION_DIE");
6122 if(IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
))
6124 SHOWMSG("no locks or files pending; quitting");
6130 SHOWMSG("locks or files still pending; cannot quit yet");
6133 res2
= ERROR_OBJECT_IN_USE
;
6139 case ACTION_CURRENT_VOLUME
:
6140 /* (Ignore) -> VolumeNode */
6142 res1
= (IPTR
)MKBADDR(VolumeNode
);
6145 case ACTION_LOCATE_OBJECT
:
6146 /* Lock,Name,Mode -> Lock */
6148 res1
= (IPTR
)Action_LocateObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
6151 case ACTION_RENAME_DISK
:
6154 res1
= Action_RenameDisk((UBYTE
*)BADDR(dp
->dp_Arg1
),&res2
);
6157 case ACTION_FREE_LOCK
:
6160 res1
= Action_FreeLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6163 case ACTION_DELETE_OBJECT
:
6164 /* Lock,Name -> Bool */
6166 res1
= Action_DeleteObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
6169 case ACTION_RENAME_OBJECT
:
6170 /* Source lock,source name,destination lock,destination name -> Bool */
6172 res1
= Action_RenameObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),BADDR(dp
->dp_Arg2
),
6173 (struct FileLock
*)BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
6177 case ACTION_MORE_CACHE
:
6178 /* Buffer delta -> Total number of buffers */
6180 /* NOTE: documentation for this packet type is inconsistent;
6181 * in the 'good old' 1.x days 'res1' was documented as
6182 * the total number of buffers to be returned. In the
6183 * 2.x documentation it is said that 'res1' should
6184 * return the success code, with 'res2' to hold the
6185 * total number of buffers. However, the 'AddBuffers'
6186 * shell command doesn't work that way, and the
6187 * dos.library implementation of 'AddBuffers()' doesn't
6188 * work that way either. The 1.3 'AddBuffers' command
6189 * appears to treat a zero result as failure and a
6190 * non-zero result as success, which suggests that this
6191 * is how the packet is supposed to work, contrary to
6192 * what the official documentation says.
6194 res1
= Action_MoreCache(dp
->dp_Arg1
,&res2
);
6197 case ACTION_COPY_DIR
:
6200 res1
= (IPTR
)Action_CopyDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6203 case ACTION_SET_PROTECT
:
6204 /* (Ignore),Lock,Name,Mask -> Bool */
6206 res1
= Action_SetProtect((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),dp
->dp_Arg4
,&res2
);
6209 case ACTION_CREATE_DIR
:
6210 /* Lock,Name -> Lock */
6212 res1
= (IPTR
)Action_CreateDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
6215 case ACTION_EXAMINE_OBJECT
:
6216 /* FileLock,FileInfoBlock -> Bool */
6218 res1
= Action_ExamineObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6221 case ACTION_EXAMINE_NEXT
:
6222 /* FileLock,FileInfoBlock -> Bool */
6224 res1
= Action_ExamineNext((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6227 case ACTION_DISK_INFO
:
6228 /* InfoData -> Bool */
6230 Action_DiskInfo((struct InfoData
*)BADDR(dp
->dp_Arg1
),&res2
);
6236 /* FileLock,InfoData -> Bool */
6238 res1
= Action_Info((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct InfoData
*)BADDR(dp
->dp_Arg2
),&res2
);
6241 case ACTION_SET_COMMENT
:
6242 /* (Ignore),FileLock,Name,Comment -> Bool */
6244 res1
= Action_SetComment((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
6250 res1
= (IPTR
)Action_Parent((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
6253 case ACTION_INHIBIT
:
6255 SHOWMSG("ACTION_INHIBIT");
6259 case ACTION_SET_DATE
:
6260 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
6262 res1
= Action_SetDate((struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),(struct DateStamp
*)dp
->dp_Arg4
,&res2
);
6265 case ACTION_SAME_LOCK
:
6266 /* Lock,Lock -> Bool */
6268 res1
= Action_SameLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
6272 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6274 res1
= Action_Read((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6278 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
6280 res1
= Action_Write((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6283 case ACTION_FINDUPDATE
:
6284 case ACTION_FINDINPUT
:
6285 case ACTION_FINDOUTPUT
:
6286 /* FileHandle,FileLock,Name -> Bool */
6288 res1
= Action_Find(dp
->dp_Action
,(struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),&res2
);
6292 /* FileHandle->fh_Arg1 -> Bool */
6294 res1
= Action_End((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6298 /* FileHandle->fh_Arg1,Position,Mode -> Position */
6300 res1
= Action_Seek((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6303 case ACTION_SET_FILE_SIZE
:
6304 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
6306 res1
= Action_SetFileSize((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6309 case ACTION_WRITE_PROTECT
:
6310 /* Flag,Key -> Bool */
6312 res1
= Action_WriteProtect(dp
->dp_Arg1
,dp
->dp_Arg2
,&res2
);
6315 case ACTION_FH_FROM_LOCK
:
6316 /* FileHandle(BPTR),FileLock -> Bool */
6318 res1
= Action_FHFromLock((struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
6321 case ACTION_IS_FILESYSTEM
:
6323 SHOWMSG("ACTION_IS_FILESYSTEM");
6327 case ACTION_CHANGE_MODE
:
6328 /* Type,Object,Mode -> Bool */
6330 res1
= Action_ChangeMode(dp
->dp_Arg1
,(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
6333 case ACTION_COPY_DIR_FH
:
6334 /* FileHandle->fh_Arg1 -> Bool */
6336 res1
= (IPTR
)Action_CopyDirFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6339 case ACTION_PARENT_FH
:
6340 /* FileHandle->fh_Arg1 -> Bool */
6342 res1
= (IPTR
)Action_ParentFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
6345 case ACTION_EXAMINE_ALL
:
6346 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6348 res1
= Action_ExamineAll((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct ExAllData
*)dp
->dp_Arg2
,
6349 dp
->dp_Arg3
,dp
->dp_Arg4
,(struct ExAllControl
*)dp
->dp_Arg5
,&res2
);
6353 case ACTION_EXAMINE_FH
:
6354 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
6356 res1
= Action_ExamineFH((struct FileNode
*)dp
->dp_Arg1
,(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
6359 case ACTION_EXAMINE_ALL_END
:
6360 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
6365 case ACTION_LOCK_RECORD
:
6366 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
6367 res1
= Action_LockRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,dp
->dp_Arg4
,(ULONG
)dp
->dp_Arg5
,&res2
);
6370 case ACTION_FREE_RECORD
:
6371 /* FileHandle->fh_Arg1,position,length -> Bool */
6372 res1
= Action_FreeRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
6377 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp
->dp_Action
,dp
->dp_Action
));
6380 res2
= ERROR_ACTION_NOT_KNOWN
;
6388 ReplyPkt(dp
,res1
,res2
);
6396 if(signals
& SIGBREAKF_CTRL_F
)
6398 struct FileNode
* fn
;
6399 struct LockNode
* ln
;
6401 D(("list of open files:"));
6403 for(fn
= (struct FileNode
*)FileList
.mlh_Head
;
6404 fn
->fn_MinNode
.mln_Succ
!= NULL
;
6405 fn
= (struct FileNode
*)fn
->fn_MinNode
.mln_Succ
)
6407 D((" name='%s'",fn
->fn_FullName
));
6408 D((" mode=%ld, offset=%ld",fn
->fn_Mode
,fn
->fn_Offset
));
6412 D(("list of allocated locks:"));
6414 for(ln
= (struct LockNode
*)LockList
.mlh_Head
;
6415 ln
->ln_MinNode
.mln_Succ
!= NULL
;
6416 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
6418 D((" name='%s'",ln
->ln_FullName
));
6419 D((" mode=%ld",ln
->ln_FileLock
.fl_Access
));
6426 if(signals
& SIGBREAKF_CTRL_C
)
6431 if(IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
))
6433 SHOWMSG("no locks or files pending; quitting");
6438 SHOWMSG("locks or files still pending; cannot quit yet");
6445 LocalPrintf("stopped.\n");
6450 /****************************************************************************/
6453 * Copy src to string dst of size siz. At most siz-1 characters
6454 * will be copied. Always NUL terminates (unless siz == 0).
6455 * Returns strlen(src); if retval >= siz, truncation occurred.
6458 strlcpy(char *dst
, const char *src
, size_t siz
)
6461 const char *s
= src
;
6465 /* Copy as many bytes as will fit */
6466 if(n
!= 0 && --n
!= 0)
6470 if(((*d
++) = (*s
++)) == '\0')
6476 /* Not enough room in dst, add NUL and traverse rest of src */
6480 (*d
) = '\0'; /* NUL-terminate dst */
6482 while((*s
++) != '\0')
6486 result
= s
- src
- 1; /* count does not include NUL */
6492 * Appends src to string dst of size siz (unlike strncat, siz is the
6493 * full size of dst, not space left). At most siz-1 characters
6494 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
6495 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
6496 * If retval >= siz, truncation occurred.
6499 strlcat(char *dst
, const char *src
, size_t siz
)
6502 const char *s
= src
;
6507 /* Find the end of dst and adjust bytes left but don't go past end */
6508 while(n
-- != 0 && (*d
) != '\0')
6516 result
= dlen
+ strlen(s
);
6533 result
= dlen
+ (s
- src
); /* count does not include NUL */