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>
9 * Copyright (C) 2011-2014, The AROS Development Team
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /****************************************************************************/
30 #include "smb_abstraction.h"
32 /****************************************************************************/
36 /****************************************************************************/
38 #if defined(__amigaos4__) && !defined(Flush)
39 #define Flush(fh) FFlush(fh)
40 #endif /* __amigaos4__ && !Flush */
42 /****************************************************************************/
44 /* A quick workaround for the timeval/timerequest->TimeVal/TimeRequest
45 change in the recent OS4 header files. */
46 #if defined(__NEW_TIMEVAL_DEFINITION_USED__)
48 #define timeval TimeVal
49 #define tv_secs Seconds
50 #define tv_micro Microseconds
52 #define timerequest TimeRequest
53 #define tr_node Request
56 #endif /* __NEW_TIMEVAL_DEFINITION_USED__ */
58 /****************************************************************************/
60 /* This is for backwards compatibility only. */
61 #if defined(__amigaos4__)
62 #define fib_EntryType fib_Obsolete
63 #endif /* __amigaos4__ */
65 /****************************************************************************/
67 #if !defined(__AROS__)
68 #include "smbfs_rev.h"
69 STRPTR Version
= VERSTAG
;
72 CONST TEXT HandlerName
[] = "smb-handler";
74 /****************************************************************************/
76 #define UNIX_TIME_OFFSET 252460800
77 #define MAX_FILENAME_LEN 256
79 /****************************************************************************/
81 #define SMB_ROOT_DIR_NAME "\\"
82 #define SMB_PATH_SEPARATOR '\\'
84 /****************************************************************************/
87 typedef LONG
* NUMBER
;
90 /****************************************************************************/
94 struct MinNode fn_MinNode
;
95 struct FileHandle
* fn_Handle
;
98 smba_file_t
* fn_File
;
104 struct MinNode ln_MinNode
;
105 struct FileLock ln_FileLock
;
106 smba_file_t
* ln_File
;
107 BOOL ln_RestartExamine
;
112 /****************************************************************************/
114 /* The minimum operating system version we require to work. */
115 #define MINIMUM_OS_VERSION 37 /* Kickstart 2.04 or better */
116 /*#define MINIMUM_OS_VERSION 39*/ /* Kickstart 3.0 or better */
118 /****************************************************************************/
120 /* Careful: the memory pool routines in amiga.lib are available only to
121 * SAS/C and similar compilers (not necessarily to GCC).
123 #if defined(__GNUC__) && (MINIMUM_OS_VERSION < 39)
125 #undef MINIMUM_OS_VERSION
126 #define MINIMUM_OS_VERSION 39
128 #endif /* __GNUC__ */
130 /****************************************************************************/
132 #if (MINIMUM_OS_VERSION < 39)
134 /* These are in amiga.lib */
135 APTR ASM
AsmCreatePool(REG(d0
,ULONG memFlags
),REG(d1
,ULONG puddleSize
),REG(d2
,ULONG threshSize
),REG(a6
,struct Library
* SysBase
));
136 VOID ASM
AsmDeletePool(REG(a0
,APTR poolHeader
),REG(a6
,struct Library
* SysBase
));
137 APTR ASM
AsmAllocPooled(REG(a0
,APTR poolHeader
),REG(d0
,ULONG memSize
),REG(a6
,struct Library
* SysBase
));
138 VOID ASM
AsmFreePooled(REG(a0
,APTR poolHeader
),REG(a1
,APTR memory
),REG(d0
,ULONG memSize
),REG(a6
,struct Library
* SysBase
));
140 #define CreatePool(memFlags,puddleSize,threshSize) AsmCreatePool((memFlags),(puddleSize),(threshSize),SysBase)
141 #define DeletePool(poolHeader) AsmDeletePool((poolHeader),SysBase)
142 #define AllocPooled(poolHeader,memSize) AsmAllocPooled((poolHeader),(memSize),SysBase)
143 #define FreePooled(poolHeader,memory,memSize) AsmFreePooled((poolHeader),(memory),(memSize),SysBase)
145 #endif /* MINIMUM_OS_VERSION */
147 /****************************************************************************/
149 /* Forward declarations for local routines. */
151 LONG VARARGS68K
LocalPrintf(STRPTR format
, ...);
152 STRPTR
amitcp_strerror(int error
);
153 STRPTR
host_strerror(int error
);
154 LONG
CompareNames(STRPTR a
, STRPTR b
);
155 VOID
StringToUpper(STRPTR s
);
157 VOID VARARGS68K
ReportError(STRPTR fmt
, ...);
159 VOID
FreeMemory(APTR address
);
160 APTR
AllocateMemory(ULONG size
);
161 LONG
GetTimeZoneDelta(VOID
);
162 ULONG
GetCurrentTime(VOID
);
163 VOID
GMTime(time_t seconds
, struct tm
*tm
);
164 time_t MakeTime(const struct tm
*const tm
);
166 VOID VARARGS68K
SPrintf(STRPTR buffer
, STRPTR formatString
, ...);
168 int BroadcastNameQuery(char *name
, char *scope
, UBYTE
*address
);
170 /****************************************************************************/
172 INLINE STATIC BOOL
ReallyRemoveDosEntry(struct DosList
*entry
);
173 INLINE STATIC LONG
BuildFullName(STRPTR parent_name
, STRPTR name
, STRPTR
*result_ptr
, LONG
*result_size_ptr
);
174 INLINE STATIC VOID
TranslateCName(UBYTE
*name
, UBYTE
*map
);
175 INLINE STATIC VOID
ConvertCString(LONG max_len
, APTR bstring
, STRPTR cstring
);
176 STATIC VOID
DisplayErrorList(VOID
);
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 opt_password
, BOOL opt_changecase
, LONG
*opt_time_zone_offset
, LONG
*opt_dst_offset
, STRPTR translation_file
);
187 STATIC BOOL
AddVolume(STRPTR service
, STRPTR workgroup
, STRPTR username
, STRPTR opt_password
, STRPTR opt_clientname
, STRPTR opt_servername
, int opt_cachesize
, STRPTR device_name
, STRPTR volume_name
);
188 STATIC VOID
ConvertBString(LONG max_len
, STRPTR cstring
, APTR bstring
);
189 STATIC BOOL
Action_Startup(struct FileSysStartupMsg
*fssm
, struct DosList
*device_node
, SIPTR
*error_ptr
);
190 STATIC BPTR
Action_Parent(struct FileLock
*parent
, SIPTR
*error_ptr
);
191 STATIC LONG
Action_DeleteObject(struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
192 STATIC BPTR
Action_CreateDir(struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
193 STATIC BPTR
Action_LocateObject(struct FileLock
*parent
, APTR bcpl_name
, LONG mode
, SIPTR
*error_ptr
);
194 STATIC BPTR
Action_CopyDir(struct FileLock
*lock
, SIPTR
*error_ptr
);
195 STATIC LONG
Action_FreeLock(struct FileLock
*lock
, SIPTR
*error_ptr
);
196 STATIC LONG
Action_SameLock(struct FileLock
*lock1
, struct FileLock
*lock2
, SIPTR
*error_ptr
);
197 STATIC LONG
Action_SetProtect(struct FileLock
*parent
, APTR bcpl_name
, LONG mask
, SIPTR
*error_ptr
);
198 STATIC LONG
Action_RenameObject(struct FileLock
*source_lock
, APTR source_bcpl_name
, struct FileLock
*destination_lock
, APTR destination_bcpl_name
, SIPTR
*error_ptr
);
199 STATIC LONG
Action_DiskInfo(struct InfoData
*id
, SIPTR
*error_ptr
);
200 STATIC LONG
Action_Info(struct FileLock
*lock
, struct InfoData
*id
, SIPTR
*error_ptr
);
201 STATIC LONG
Action_ExamineObject(struct FileLock
*lock
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
202 STATIC BOOL
NameIsAcceptable(STRPTR name
, LONG max_len
);
203 STATIC LONG
Action_ExamineNext(struct FileLock
*lock
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
204 STATIC LONG
Action_ExamineAll(struct FileLock
*lock
, struct ExAllData
*ed
, ULONG size
, ULONG type
, struct ExAllControl
*eac
, SIPTR
*error_ptr
);
205 STATIC LONG
Action_Find(LONG action
, struct FileHandle
*fh
, struct FileLock
*parent
, APTR bcpl_name
, SIPTR
*error_ptr
);
206 STATIC LONG
Action_Read(struct FileNode
*fn
, APTR mem
, LONG length
, SIPTR
*error_ptr
);
207 STATIC LONG
Action_Write(struct FileNode
*fn
, APTR mem
, LONG length
, SIPTR
*error_ptr
);
208 STATIC LONG
Action_End(struct FileNode
*fn
, SIPTR
*error_ptr
);
209 STATIC LONG
Action_Seek(struct FileNode
*fn
, LONG position
, LONG mode
, SIPTR
*error_ptr
);
210 STATIC LONG
Action_SetFileSize(struct FileNode
*fn
, LONG position
, LONG mode
, SIPTR
*error_ptr
);
211 STATIC LONG
Action_SetDate(struct FileLock
*parent
, APTR bcpl_name
, struct DateStamp
*ds
, SIPTR
*error_ptr
);
212 STATIC LONG
Action_ExamineFH(struct FileNode
*fn
, struct FileInfoBlock
*fib
, SIPTR
*error_ptr
);
213 STATIC BPTR
Action_ParentFH(struct FileNode
*fn
, SIPTR
*error_ptr
);
214 STATIC BPTR
Action_CopyDirFH(struct FileNode
*fn
, SIPTR
*error_ptr
);
215 STATIC LONG
Action_FHFromLock(struct FileHandle
*fh
, struct FileLock
*fl
, SIPTR
*error_ptr
);
216 STATIC LONG
Action_RenameDisk(APTR bcpl_name
, SIPTR
*error_ptr
);
217 STATIC LONG
Action_ChangeMode(LONG type
, APTR object
, LONG new_mode
, SIPTR
*error_ptr
);
218 STATIC LONG
Action_WriteProtect(LONG flag
, ULONG key
, SIPTR
*error_ptr
);
219 STATIC LONG
Action_MoreCache(LONG buffer_delta
, SIPTR
*error_ptr
);
220 STATIC LONG
Action_SetComment(struct FileLock
*parent
, APTR bcpl_name
, APTR bcpl_comment
, SIPTR
*error_ptr
);
221 STATIC LONG
Action_LockRecord(struct FileNode
*fn
, LONG offset
, LONG length
, LONG mode
, ULONG timeout
, SIPTR
*error_ptr
);
222 STATIC LONG
Action_FreeRecord(struct FileNode
*fn
, LONG offset
, LONG length
, SIPTR
*error_ptr
);
223 STATIC VOID
StartReconnectTimer(VOID
);
224 STATIC VOID
HandleFileSystem(VOID
);
226 /****************************************************************************/
228 #if !defined(__AROS__)
229 struct Library
* SysBase
;
231 struct Library
* DOSBase
;
232 struct Library
* UtilityBase
;
233 struct Library
* IntuitionBase
;
234 struct Library
* SocketBase
;
235 struct Library
* LocaleBase
;
236 struct Library
* TimerBase
;
237 struct Library
* IconBase
;
239 /****************************************************************************/
241 #if defined(__amigaos4__)
243 /****************************************************************************/
245 struct ExecIFace
* IExec
;
246 struct DOSIFace
* IDOS
;
247 struct UtilityIFace
* IUtility
;
248 struct IntuitionIFace
* IIntuition
;
249 struct SocketIFace
* ISocket
;
250 struct LocaleIFace
* ILocale
;
251 struct TimerIFace
* ITimer
;
252 struct IconIFace
* IIcon
;
254 /****************************************************************************/
256 #endif /* __amigaos4__ */
258 /****************************************************************************/
260 STATIC
struct timerequest TimerRequest
;
261 STATIC BOOL TimerActive
;
263 /****************************************************************************/
265 struct Locale
* Locale
;
267 /****************************************************************************/
269 #if !defined(__AROS__)
276 /****************************************************************************/
278 STATIC
struct DosList
* DeviceNode
;
279 STATIC
struct DosList
* VolumeNode
;
280 STATIC BOOL VolumeNodeAdded
;
281 STATIC
struct MsgPort
* FileSystemPort
;
283 STATIC smba_server_t
* ServerData
;
287 STATIC BOOL CaseSensitive
;
288 STATIC BOOL OmitHidden
;
290 STATIC LONG DSTOffset
;
291 STATIC LONG TimeZoneOffset
;
292 STATIC BOOL OverrideLocaleTimeZone
;
294 STATIC BOOL WriteProtected
;
295 STATIC ULONG WriteProtectKey
;
297 STATIC
struct MinList FileList
;
298 STATIC
struct MinList LockList
;
300 STATIC APTR MemoryPool
;
302 STATIC
struct RDArgs
* Parameters
;
303 STATIC
struct DiskObject
* Icon
;
305 STATIC
struct WBStartup
* WBStartup
;
307 STATIC
struct MinList ErrorList
;
309 STATIC BOOL TranslateNames
;
310 STATIC UBYTE A2M
[256];
311 STATIC UBYTE M2A
[256];
319 SWITCH CaseSensitive
;
328 NUMBER TimeZoneOffset
;
334 CONST TEXT control_template
[] =
335 "DOMAIN=WORKGROUP/K,"
339 "CASE=CASESENSITIVE/S,"
342 "CLIENT=CLIENTNAME/K,"
343 "SERVER=SERVERNAME/K,"
344 "DEVICE=DEVICENAME/K,"
345 "VOLUME=VOLUMENAME/K,"
346 "CACHE=CACHESIZE/N/K,"
347 "DEBUGLEVEL=DEBUG/N/K,"
348 "TZ=TIMEZONEOFFSET/N/K,"
350 "TRANSLATE=TRANSLATIONFILE/K,"
353 /****************************************************************************/
357 LONG result
= RETURN_OK
;
359 #if !defined(__AROS__)
360 SysBase
= (struct Library
*)AbsExecBase
;
362 #if defined(__amigaos4__)
364 IExec
= (struct ExecIFace
*)((struct ExecBase
*)SysBase
)->MainInterface
;
366 #endif /* __amigaos4__ */
369 FileSystemPort
= &((*(struct Process
*)FindTask(NULL
)).pr_MsgPort
);
371 /* Don't emit any debugging output before we are ready. */
374 /* Open the libraries we need and check
375 * whether we could get them.
377 DOSBase
= OpenLibrary("dos.library",0);
379 #if defined(__amigaos4__)
383 IDOS
= (struct DOSIFace
*)GetInterface(DOSBase
, "main", 1, 0);
386 CloseLibrary(DOSBase
);
391 #endif /* __amigaos4__ */
393 UtilityBase
= OpenLibrary("utility.library",37);
395 #if defined(__amigaos4__)
397 if(UtilityBase
!= NULL
)
399 IUtility
= (struct UtilityIFace
*)GetInterface(UtilityBase
, "main", 1, 0);
402 CloseLibrary(UtilityBase
);
407 #endif /* __amigaos4__ */
409 if(UtilityBase
== NULL
|| DOSBase
== NULL
|| DOSBase
->lib_Version
< MINIMUM_OS_VERSION
)
412 /* This needs to be set up properly for ReportError()
415 NewList((struct List
*)&ErrorList
);
418 SHOWVALUE(Locale
->loc_GMTOffset
);
429 /****************************************************************************/
432 #define LocalPrintf(format,args...) Printf(format ,##args )
435 LocalPrintf(STRPTR format
, ...)
440 #if defined(__amigaos4__)
442 va_startlinear(args
,format
);
443 result
= VPrintf(format
,va_getlinearva(args
,APTR
));
448 va_start(args
,format
);
449 result
= VPrintf(format
,args
);
452 #endif /* __amigaos4__ */
456 #endif /* __AROS__ */
458 /****************************************************************************/
460 /* Obtain the descriptive text corresponding to an error number
461 * that may have been generated by the TCP/IP stack.
464 amitcp_strerror(int error
)
466 struct TagItem tags
[2];
471 tags
[0].ti_Tag
= SBTM_GETVAL(SBTC_ERRNOSTRPTR
);
472 tags
[0].ti_Data
= error
;
473 tags
[1].ti_Tag
= TAG_END
;
475 SocketBaseTagList(tags
);
477 result
= (STRPTR
)tags
[0].ti_Data
;
483 /****************************************************************************/
485 /* Return the descriptive text associated with a host lookup failure code. */
487 host_strerror(int error
)
489 struct TagItem tags
[2];
494 tags
[0].ti_Tag
= SBTM_GETVAL(SBTC_HERRNOSTRPTR
);
495 tags
[0].ti_Data
= error
;
496 tags
[1].ti_Tag
= TAG_END
;
498 SocketBaseTagList(tags
);
500 result
= (STRPTR
)tags
[0].ti_Data
;
506 /****************************************************************************/
508 /* Compare two strings, either case sensitive or not
509 * sensitive to the case of the letters. How this is
510 * to be done is controlled by a global option. This
511 * routine is called whenever two SMB file names are
515 CompareNames(STRPTR a
,STRPTR b
)
520 result
= strcmp(a
,b
);
522 result
= Stricmp(a
,b
);
527 /****************************************************************************/
529 /* Translate a string into all upper case characters. */
531 StringToUpper(STRPTR s
)
535 while((c
= (*s
)) != '\0')
539 /****************************************************************************/
541 /* Prepare the accumulated list of error messages for display
542 * and purge the contents of that list.
545 DisplayErrorList(VOID
)
547 struct MinNode
* last
= NULL
;
553 /* Determine how much memory will have to be
554 * allocated to hold all the accumulated
559 for(mn
= ErrorList
.mlh_Head
;
560 mn
->mln_Succ
!= NULL
;
565 msg
= (STRPTR
)(mn
+ 1);
567 len
+= strlen(msg
)+1;
570 /* Allocate the memory for the messages, then
575 str
= AllocVec(len
,MEMF_ANY
);
580 for(mn
= ErrorList
.mlh_Head
;
581 mn
->mln_Succ
!= NULL
;
584 msg
= (STRPTR
)(mn
+ 1);
593 /* Purge the list. */
594 while((mn
= (struct MinNode
*)RemHead((struct List
*)&ErrorList
)) != NULL
)
597 /* Display the error messages. */
600 IntuitionBase
= OpenLibrary("intuition.library",37);
602 #if defined(__amigaos4__)
604 if(IntuitionBase
!= NULL
)
606 IIntuition
= (struct IntuitionIFace
*)GetInterface(IntuitionBase
, "main", 1, 0);
607 if(IIntuition
== NULL
)
609 CloseLibrary(IntuitionBase
);
610 IntuitionBase
= NULL
;
614 #endif /* __amigaos4__ */
616 if(IntuitionBase
!= NULL
)
618 struct EasyStruct es
;
620 memset(&es
,0,sizeof(es
));
622 es
.es_StructSize
= sizeof(es
);
624 es
.es_TextFormat
= str
;
625 es
.es_GadgetFormat
= "Ok";
627 EasyRequestArgs(NULL
,&es
,NULL
,NULL
);
633 #if defined(__amigaos4__)
635 if(IIntuition
!= NULL
)
637 DropInterface((struct Interface
*)IIntuition
);
641 #endif /* __amigaos4__ */
643 CloseLibrary(IntuitionBase
);
644 IntuitionBase
= NULL
;
647 /****************************************************************************/
649 /* Release memory allocated from the global pool. */
651 FreeMemory(APTR address
)
655 ULONG
* mem
= address
;
659 if(GETDEBUGLEVEL() > 0)
660 memset(address
,0xA3,mem
[-1] - sizeof(*mem
));
664 FreePooled(MemoryPool
,&mem
[-1],mem
[-1]);
668 /* Allocate memory from the global pool. */
670 AllocateMemory(ULONG size
)
678 size
= (sizeof(*mem
) + size
+ 7) & ~7UL;
680 mem
= AllocPooled(MemoryPool
,size
);
687 if(GETDEBUGLEVEL() > 0)
688 memset(mem
,0xA5,mem
[-1] - sizeof(*mem
));
699 /****************************************************************************/
701 /* Obtain the number of seconds to add to the current time
702 * to translate local time into UTC.
705 GetTimeZoneDelta(VOID
)
709 if(OverrideLocaleTimeZone
)
711 seconds
= 60 * TimeZoneOffset
;
713 else if (Locale
!= NULL
)
715 /* The GMT offset actually is the number of minutes to add to
716 * the local time to yield Greenwich Mean Time. It is negative
717 * for all time zones east of the Greenwich meridian and
718 * positive for all time zones west of it.
720 seconds
= 60 * Locale
->loc_GMTOffset
;
727 return(seconds
+ DSTOffset
);
730 /****************************************************************************/
732 /* Obtain the current time, in standard Unix format, adjusted for the
741 GetSysTime((APTR
)&tv
);
743 result
= UNIX_TIME_OFFSET
+ GetTimeZoneDelta() + tv
.tv_secs
;
748 /****************************************************************************/
750 /* Fill in a 'tm' type time specification with time information
751 * corresponding to the number of seconds provided. Input is
755 GMTime(time_t seconds
,struct tm
* tm
)
757 struct ClockData clock_data
;
759 if(seconds
< UNIX_TIME_OFFSET
)
762 seconds
-= UNIX_TIME_OFFSET
;
764 Amiga2Date(seconds
,&clock_data
);
766 memset(tm
,0,sizeof(*tm
));
768 tm
->tm_sec
= clock_data
.sec
;
769 tm
->tm_min
= clock_data
.min
;
770 tm
->tm_hour
= clock_data
.hour
;
771 tm
->tm_mday
= clock_data
.mday
;
772 tm
->tm_mon
= clock_data
.month
- 1;
773 tm
->tm_year
= clock_data
.year
- 1900;
776 /* Calculate the number of seconds that have passed since January 1st 1970
777 * based upon the time specification provided. Output is in Unix format.
780 MakeTime(const struct tm
* const tm
)
782 struct ClockData clock_data
;
785 clock_data
.sec
= tm
->tm_sec
;
786 clock_data
.min
= tm
->tm_min
;
787 clock_data
.hour
= tm
->tm_hour
;
788 clock_data
.mday
= tm
->tm_mday
;
789 clock_data
.month
= tm
->tm_mon
+ 1;
790 clock_data
.year
= tm
->tm_year
+ 1900;
792 seconds
= Date2Amiga(&clock_data
) + UNIX_TIME_OFFSET
;
797 /****************************************************************************/
799 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
800 * Thanks much, Chris!
804 unsigned short flags
;
805 unsigned char address
[4];
810 unsigned short name_trn_id
;
811 unsigned short flags
;
812 unsigned short qdcount
;
813 unsigned short ancount
;
814 unsigned short nscount
;
815 unsigned short arcount
;
819 L1_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
)
825 while(('\0' != name
[i
]) && (i
< 15))
827 k
= ToUpper(name
[i
]);
829 dst
[j
++] = 'A' + ((k
& 0xF0) >> 4);
830 dst
[j
++] = 'A' + (k
& 0x0F);
833 i
= 'A' + ((pad
& 0xF0) >> 4);
834 k
= 'A' + (pad
& 0x0F);
842 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
843 dst
[31] = 'A' + (sfx
& 0x0F);
850 L2_Encode(UBYTE
* dst
, const UBYTE
* name
, const UBYTE pad
, const UBYTE sfx
, const UBYTE
* scope
)
856 if(NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
866 for(i
= 0, j
= (lenpos
+ 1);
867 ('.' != scope
[i
]) && ('\0' != scope
[i
]);
870 dst
[j
] = ToUpper(scope
[i
]);
873 dst
[lenpos
] = (UBYTE
)i
;
877 while('.' == (*scope
++));
886 BroadcastNameQuery(char *name
, char *scope
, UBYTE
*address
)
888 static const UBYTE header
[12] =
890 0x07, 0xB0, /* 1964 == 0x07B0. */
891 0x01, 0x10, /* Binary 0 0000 0010001 0000 */
892 0x00, 0x01, /* One name query. */
893 0x00, 0x00, /* Zero answers. */
894 0x00, 0x00, /* Zero authorities. */
895 0x00, 0x00 /* Zero additional. */
898 static const UBYTE query_tail
[4] =
908 struct sockaddr_in sox
;
909 struct nmb_header nmb_header
;
918 sock_fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
921 SHOWMSG("couldn't get the socket");
926 if(setsockopt(sock_fd
, SOL_SOCKET
, SO_BROADCAST
, &option_true
, sizeof(option_true
)) < 0)
928 SHOWMSG("couldn't enable the broadcast option");
933 sox
.sin_family
= AF_INET
;
934 sox
.sin_addr
.s_addr
= htonl(0xFFFFFFFF);
936 s
= getservbyname("netbios-ns","udp");
938 sox
.sin_port
= htons(s
->s_port
);
940 sox
.sin_port
= htons(137);
942 memcpy(buffer
, header
, (total_len
= sizeof(header
)));
944 n
= L2_Encode(&buffer
[total_len
], name
, ' ', '\0', scope
);
947 SHOWMSG("name encoding failed");
953 memcpy(&buffer
[total_len
], query_tail
, sizeof(query_tail
));
954 total_len
+= sizeof(query_tail
);
959 /* Send the query packet; retry five times with a one second
962 for(i
= 0 ; i
< 5 ; i
++)
964 if(sendto(sock_fd
, (void *) buffer
, total_len
, 0, (struct sockaddr
*)&sox
, sizeof(struct sockaddr_in
)) < 0)
966 SHOWMSG("could not send the packet");
971 /* Wait for a response to arrive. */
976 FD_SET(sock_fd
,&read_fds
);
978 if(WaitSelect(sock_fd
+1, &read_fds
, NULL
, NULL
, &tv
, NULL
) > 0)
980 n
= recvfrom(sock_fd
, buffer
, sizeof(buffer
), 0, NULL
, NULL
);
983 SHOWMSG("could not pick up the response packet");
994 /* Did we get anything at all? */
995 if(n
> (int)sizeof(nmb_header
))
997 /* Check whether the query was successful. */
998 memcpy(&nmb_header
, buffer
, sizeof(nmb_header
));
999 if((nmb_header
.flags
& 0xF) == OK
)
1001 /* Find the NB/IP fields which directly follow
1004 for(i
= sizeof(header
) + strlen(&buffer
[sizeof(header
)])+1 ; i
< n
- (int)sizeof(query_tail
) ; i
++)
1006 if(memcmp(&buffer
[i
], query_tail
, sizeof(query_tail
)) == SAME
)
1010 /* This should be the start of the interesting bits;
1011 * we skip the NB/IP fields and the TTL field.
1013 start
= i
+ sizeof(query_tail
) + sizeof(long);
1016 unsigned short read_len
;
1017 struct addr_entry addr_entry
;
1019 /* This should be the read length. */
1020 memcpy(&read_len
, &buffer
[start
], 2);
1022 /* Is there any useful and readable data attached? */
1023 if(read_len
>= sizeof(addr_entry
) &&
1024 start
+ (int)sizeof(read_len
) + (int)sizeof(addr_entry
) <= n
)
1026 /* Copy a single address entry; this should be
1027 * just the one we need.
1029 memcpy(&addr_entry
, &buffer
[start
+ sizeof(read_len
)], sizeof(addr_entry
));
1031 /* Copy the address field (IPv4 only). */
1032 memcpy(address
, addr_entry
.address
, 4);
1047 CloseSocket(sock_fd
);
1053 /****************************************************************************/
1055 /* Send a disk change notification message which will be picked up
1056 * by all applications that listen for this kind of event, e.g.
1060 SendDiskChange(ULONG
class)
1062 struct IOStdReq
* input_request
= NULL
;
1063 struct MsgPort
* input_port
;
1064 struct InputEvent ie
;
1068 input_port
= CreateMsgPort();
1069 if(input_port
== NULL
)
1072 input_request
= (struct IOStdReq
*)CreateIORequest(input_port
,sizeof(*input_request
));
1073 if(input_request
== NULL
)
1076 if(OpenDevice("input.device",0,(struct IORequest
*)input_request
,0) != OK
)
1079 memset(&ie
,0,sizeof(ie
));
1081 ie
.ie_Class
= class;
1082 ie
.ie_Qualifier
= IEQUALIFIER_MULTIBROADCAST
;
1084 GetSysTime(&ie
.ie_TimeStamp
);
1086 input_request
->io_Command
= IND_WRITEEVENT
;
1087 input_request
->io_Data
= &ie
;
1088 input_request
->io_Length
= sizeof(ie
);
1090 DoIO((struct IORequest
*)input_request
);
1094 if(input_request
!= NULL
)
1096 if(input_request
->io_Device
!= NULL
)
1097 CloseDevice((struct IORequest
*)input_request
);
1099 DeleteIORequest((struct IORequest
*)input_request
);
1102 DeleteMsgPort(input_port
);
1107 /****************************************************************************/
1109 /* Find the file node corresponding to a given name,
1110 * skipping a particular entry if necessary.
1112 STATIC
struct FileNode
*
1113 FindFileNode(STRPTR name
,struct FileNode
* skip
)
1115 struct FileNode
* result
= NULL
;
1116 struct FileNode
* fn
;
1118 for(fn
= (struct FileNode
*)FileList
.mlh_Head
;
1119 fn
->fn_MinNode
.mln_Succ
!= NULL
;
1120 fn
= (struct FileNode
*)fn
->fn_MinNode
.mln_Succ
)
1122 if(fn
!= skip
&& CompareNames(name
,fn
->fn_FullName
) == SAME
)
1132 /* Find the lock node corresponding to a given name,
1133 * skipping a particular entry if necessary.
1135 STATIC
struct LockNode
*
1136 FindLockNode(STRPTR name
,struct LockNode
* skip
)
1138 struct LockNode
* result
= NULL
;
1139 struct LockNode
* ln
;
1141 for(ln
= (struct LockNode
*)LockList
.mlh_Head
;
1142 ln
->ln_MinNode
.mln_Succ
!= NULL
;
1143 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
1145 if(ln
!= skip
&& CompareNames(name
,ln
->ln_FullName
) == SAME
)
1155 /* Check whether a new reference to be made to a named
1156 * file will cause a conflict of access modes. No two
1157 * files and locks may refer to the same object if
1158 * either of these references is made in exclusive
1159 * mode. This is the case which this function is
1163 CheckAccessModeCollision(STRPTR name
,LONG mode
)
1165 struct LockNode
* ln
;
1166 struct FileNode
* fn
;
1172 fn
= FindFileNode(name
,NULL
);
1175 if(mode
!= SHARED_LOCK
|| fn
->fn_Mode
!= SHARED_LOCK
)
1177 D(("collides with '%s'",fn
->fn_FullName
));
1178 error
= ERROR_OBJECT_IN_USE
;
1183 ln
= FindLockNode(name
,NULL
);
1186 if(mode
!= SHARED_LOCK
|| ln
->ln_FileLock
.fl_Access
!= SHARED_LOCK
)
1188 D(("collides with '%s'",ln
->ln_FullName
));
1189 error
= ERROR_OBJECT_IN_USE
;
1200 /* Find out whether there already exists a reference to a
1201 * certain file or directory.
1204 NameAlreadyInUse(STRPTR name
)
1210 if(FindFileNode(name
,NULL
) != NULL
)
1212 error
= ERROR_OBJECT_IN_USE
;
1216 if(FindLockNode(name
,NULL
) != NULL
)
1218 error
= ERROR_OBJECT_IN_USE
;
1228 /* Check whether an Amiga file name uses special characters which
1229 * should be avoided when used with the SMB file sharing protocol.
1232 IsReservedName(STRPTR name
)
1234 BOOL result
= FALSE
;
1236 /* Disallow "." and "..". */
1237 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
1245 /* Disallow the use of the backslash in file names. */
1246 while((c
= (*name
++)) != '\0')
1248 if(c
== SMB_PATH_SEPARATOR
)
1259 /****************************************************************************/
1261 /* Convert a POSIX error code into an AmigaDOS error code. */
1263 MapErrnoToIoErr(int error
)
1265 /* Not all of these mappings make good sense; bear in mind that
1266 * POSIX covers more than a hundred different error codes
1267 * whereas with AmigaDOS we're stranded with a measly 48...
1269 STATIC
const LONG Map
[][2] =
1271 { EPERM
, ERROR_OBJECT_NOT_FOUND
}, /* Operation not permitted */
1272 { ENOENT
, ERROR_OBJECT_NOT_FOUND
}, /* No such file or directory */
1273 { ESRCH
, ERROR_OBJECT_NOT_FOUND
}, /* No such process */
1274 { EINTR
, ERROR_BREAK
}, /* Interrupted system call */
1275 { EIO
, ERROR_OBJECT_IN_USE
}, /* Input/output error */
1276 { E2BIG
, ERROR_TOO_MANY_ARGS
}, /* Argument list too long */
1277 { EBADF
, ERROR_INVALID_LOCK
}, /* Bad file descriptor */
1278 { ENOMEM
, ERROR_NO_FREE_STORE
}, /* Cannot allocate memory */
1279 { EACCES
, ERROR_OBJECT_IN_USE
}, /* Permission denied */
1281 { ENOTBLK
, ERROR_OBJECT_WRONG_TYPE
}, /* Block device required */
1283 { EBUSY
, ERROR_OBJECT_IN_USE
}, /* Device busy */
1284 { EEXIST
, ERROR_OBJECT_EXISTS
}, /* File exists */
1285 { EXDEV
, ERROR_NOT_IMPLEMENTED
}, /* Cross-device link */
1286 { ENOTDIR
, ERROR_OBJECT_WRONG_TYPE
}, /* Not a directory */
1287 { EISDIR
, ERROR_OBJECT_WRONG_TYPE
}, /* Is a directory */
1288 { EINVAL
, ERROR_BAD_NUMBER
}, /* Invalid argument */
1289 { EFBIG
, ERROR_DISK_FULL
}, /* File too large */
1290 { ENOSPC
, ERROR_DISK_FULL
}, /* No space left on device */
1291 { ESPIPE
, ERROR_SEEK_ERROR
}, /* Illegal seek */
1292 { EROFS
, ERROR_WRITE_PROTECTED
}, /* Read-only file system */
1293 { EMLINK
, ERROR_TOO_MANY_LEVELS
}, /* Too many links */
1294 { ENOTSOCK
, ERROR_OBJECT_WRONG_TYPE
}, /* Socket operation on non-socket */
1295 { EDESTADDRREQ
, ERROR_REQUIRED_ARG_MISSING
}, /* Destination address required */
1296 { EMSGSIZE
, ERROR_LINE_TOO_LONG
}, /* Message too long */
1297 { EPROTOTYPE
, ERROR_BAD_TEMPLATE
}, /* Protocol wrong type for socket */
1298 { ENOPROTOOPT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol not available */
1299 { EPROTONOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol not supported */
1300 { ESOCKTNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Socket type not supported */
1301 { EOPNOTSUPP
, ERROR_NOT_IMPLEMENTED
}, /* Operation not supported */
1302 { EPFNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Protocol family not supported */
1303 { EAFNOSUPPORT
, ERROR_NOT_IMPLEMENTED
}, /* Address family not supported by protocol family */
1304 { EADDRINUSE
, ERROR_OBJECT_IN_USE
}, /* Address already in use */
1305 { EADDRNOTAVAIL
, ERROR_OBJECT_NOT_FOUND
}, /* Can't assign requested address */
1306 { ENETDOWN
, ERROR_OBJECT_NOT_FOUND
}, /* Network is down */
1307 { ENETUNREACH
, ERROR_OBJECT_NOT_FOUND
}, /* Network is unreachable */
1308 { ENETRESET
, ERROR_OBJECT_NOT_FOUND
}, /* Network dropped connection on reset */
1309 { ECONNABORTED
, ERROR_OBJECT_NOT_FOUND
}, /* Software caused connection abort */
1310 { ECONNRESET
, ERROR_OBJECT_NOT_FOUND
}, /* Connection reset by peer */
1311 { ENOBUFS
, ERROR_DISK_FULL
}, /* No buffer space available */
1312 { EISCONN
, ERROR_OBJECT_IN_USE
}, /* Socket is already connected */
1313 { ENOTCONN
, ERROR_OBJECT_WRONG_TYPE
}, /* Socket is not connected */
1314 { ESHUTDOWN
, ERROR_INVALID_LOCK
}, /* Can't send after socket shutdown */
1315 { ECONNREFUSED
, ERROR_OBJECT_IN_USE
}, /* Connection refused */
1316 { ELOOP
, ERROR_TOO_MANY_LEVELS
}, /* Too many levels of symbolic links */
1317 { ENAMETOOLONG
, ERROR_LINE_TOO_LONG
}, /* File name too long */
1318 { EHOSTDOWN
, ERROR_OBJECT_NOT_FOUND
}, /* Host is down */
1319 { EHOSTUNREACH
, ERROR_OBJECT_NOT_FOUND
}, /* No route to host */
1320 { ENOTEMPTY
, ERROR_DIRECTORY_NOT_EMPTY
}, /* Directory not empty */
1321 { EPROCLIM
, ERROR_TASK_TABLE_FULL
}, /* Too many processes */
1323 { EUSERS
, ERROR_TASK_TABLE_FULL
}, /* Too many users */
1325 { EDQUOT
, ERROR_DISK_FULL
}, /* Disc quota exceeded */
1326 { ENOLCK
, ERROR_NOT_IMPLEMENTED
}, /* no locks available */
1330 LONG result
= ERROR_ACTION_NOT_KNOWN
;
1338 for(i
= 0 ; Map
[i
][0] != -1 ; i
++)
1340 if(Map
[i
][0] == error
)
1351 /****************************************************************************/
1353 /* Translate a BCPL style file name (i.e. length is in the first byte)
1354 * via a mapping table.
1357 TranslateBName(UBYTE
* name
,UBYTE
* map
)
1364 #if !defined(N__AROS__)
1367 len
= AROS_BSTR_strlen(name
);
1368 name
= AROS_BSTR_ADDR(name
);
1379 /* Translate a NUL terminated file name via a mapping table. */
1381 TranslateCName(UBYTE
* name
,UBYTE
* map
)
1387 while((c
= (*name
)) != '\0')
1392 /****************************************************************************/
1394 /* Remove a DosList entry using the proper protocols. Note that
1395 * this function can fail!
1398 ReallyRemoveDosEntry(struct DosList
* entry
)
1400 struct Message
* mn
;
1401 struct MsgPort
* port
;
1402 struct DosList
* dl
;
1403 BOOL result
= FALSE
;
1406 if(entry
->dol_Type
== DLT_DEVICE
)
1411 port
= entry
->dol_Task
;
1413 for(i
= 0 ; i
< 100 ; i
++)
1415 dl
= AttemptLockDosList(LDF_WRITE
|kind
);
1423 UnLockDosList(LDF_WRITE
|kind
);
1430 while((mn
= GetMsg(port
)) != NULL
)
1431 ReplyPkt((struct DosPacket
*)mn
->mn_Node
.ln_Name
,DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
1433 Delay(TICKS_PER_SECOND
/ 10);
1439 /****************************************************************************/
1441 /* Release all resources allocated by the Setup() routine. */
1445 BOOL send_disk_change
= FALSE
;
1449 /* If any errors have cropped up, display them now before
1454 if(Parameters
!= NULL
)
1456 FreeArgs(Parameters
);
1457 FreeDosObject(DOS_RDARGS
, Parameters
);
1463 FreeDiskObject(Icon
);
1467 if(ServerData
!= NULL
)
1469 smba_disconnect(ServerData
);
1473 if(DeviceNode
!= NULL
)
1475 if(ReallyRemoveDosEntry(DeviceNode
))
1476 FreeDosEntry(DeviceNode
);
1480 if(VolumeNode
!= NULL
)
1484 if(ReallyRemoveDosEntry(VolumeNode
))
1485 FreeDosEntry(VolumeNode
);
1487 send_disk_change
= TRUE
;
1491 FreeDosEntry(VolumeNode
);
1497 if(FileSystemPort
!= NULL
)
1499 struct Message
* mn
;
1501 /* Return all queued packets; there should be none, though. */
1502 while((mn
= GetMsg(FileSystemPort
)) != NULL
)
1503 ReplyPkt((struct DosPacket
*)mn
->mn_Node
.ln_Name
,DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
1506 if(WBStartup
== NULL
&& send_disk_change
)
1507 SendDiskChange(IECLASS_DISKREMOVED
);
1509 #if defined(__amigaos4__)
1513 DropInterface((struct Interface
*)ITimer
);
1517 #endif /* __amigaos4__ */
1519 if(TimerBase
!= NULL
)
1523 AbortIO((struct IORequest
*)&TimerRequest
);
1524 WaitIO((struct IORequest
*)&TimerRequest
);
1526 CloseDevice((struct IORequest
*)&TimerRequest
);
1530 #if defined(__amigaos4__)
1534 DropInterface((struct Interface
*)ISocket
);
1538 #endif /* __amigaos4__ */
1540 if(SocketBase
!= NULL
)
1542 CloseLibrary(SocketBase
);
1546 #if defined(__amigaos4__)
1548 if(IUtility
!= NULL
)
1550 DropInterface((struct Interface
*)IUtility
);
1554 #endif /* __amigaos4__ */
1556 if(UtilityBase
!= NULL
)
1558 CloseLibrary(UtilityBase
);
1562 #if defined(__amigaos4__)
1566 DropInterface((struct Interface
*)IIcon
);
1570 #endif /* __amigaos4__ */
1572 if(IconBase
!= NULL
)
1574 CloseLibrary(IconBase
);
1580 CloseLocale(Locale
);
1584 #if defined(__amigaos4__)
1588 DropInterface((struct Interface
*)ILocale
);
1592 #endif /* __amigaos4__ */
1594 if(LocaleBase
!= NULL
)
1596 CloseLibrary(LocaleBase
);
1600 if(MemoryPool
!= NULL
)
1602 DeletePool(MemoryPool
);
1606 #if defined(__amigaos4__)
1610 DropInterface((struct Interface
*)IDOS
);
1614 #endif /* __amigaos4__ */
1618 CloseLibrary(DOSBase
);
1622 if(WBStartup
!= NULL
)
1625 ReplyMsg((struct Message
*)WBStartup
);
1631 /****************************************************************************/
1633 /* Allocate all the necessary resources to get going. */
1636 STRPTR opt_password
,
1637 BOOL opt_changecase
,
1638 LONG
* opt_time_zone_offset
,
1639 LONG
* opt_dst_offset
,
1640 STRPTR translation_file
)
1642 BOOL result
= FALSE
;
1648 NewList((struct List
*)&FileList
);
1649 NewList((struct List
*)&LockList
);
1651 MemoryPool
= CreatePool(MEMF_ANY
|MEMF_PUBLIC
,4096,4096);
1652 if(MemoryPool
== NULL
)
1654 ReportError("Could not create memory pool.");
1658 LocaleBase
= OpenLibrary("locale.library",38);
1660 #if defined(__amigaos4__)
1662 if(LocaleBase
!= NULL
)
1664 ILocale
= (struct LocaleIFace
*)GetInterface(LocaleBase
, "main", 1, 0);
1667 CloseLibrary(LocaleBase
);
1672 #endif /* __amigaos4__ */
1674 if(LocaleBase
!= NULL
)
1675 Locale
= OpenLocale(NULL
);
1677 if(opt_time_zone_offset
!= NULL
)
1679 TimeZoneOffset
= (*opt_time_zone_offset
);
1680 OverrideLocaleTimeZone
= TRUE
;
1683 if(opt_dst_offset
!= NULL
)
1684 DSTOffset
= -60 * (*opt_dst_offset
);
1686 memset(&TimerRequest
,0,sizeof(TimerRequest
));
1687 TimerActive
= FALSE
;
1689 if(OpenDevice(TIMERNAME
,UNIT_VBLANK
,(struct IORequest
*)&TimerRequest
,0) != OK
)
1691 ReportError("Could not open 'timer.device'.");
1695 TimerBase
= (struct Library
*)TimerRequest
.tr_node
.io_Device
;
1697 #if defined(__amigaos4__)
1699 if(TimerBase
!= NULL
)
1701 ITimer
= (struct TimerIFace
*)GetInterface(TimerBase
, "main", 1, 0);
1704 ReportError("Could not open 'timer.device'.");
1709 #endif /* __amigaos4__ */
1711 SocketBase
= OpenLibrary("bsdsocket.library",3);
1713 #if defined(__amigaos4__)
1715 if(SocketBase
!= NULL
)
1717 ISocket
= (struct SocketIFace
*)GetInterface(SocketBase
, "main", 1, 0);
1720 CloseLibrary(SocketBase
);
1725 #endif /* __amigaos4__ */
1727 if(SocketBase
== NULL
)
1729 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
1733 error
= SocketBaseTags(
1734 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno
))), &errno
,
1735 SBTM_SETVAL(SBTC_HERRNOLONGPTR
), &h_errno
,
1736 SBTM_SETVAL(SBTC_LOGTAGPTR
), HandlerName
,
1737 SBTM_SETVAL(SBTC_BREAKMASK
), SIGBREAKF_CTRL_C
,
1741 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error
,amitcp_strerror(error
));
1747 for(i
= 0 ; i
< (LONG
)strlen(opt_password
) ; i
++)
1748 opt_password
[i
] = ToUpper(opt_password
[i
]);
1751 TranslateNames
= FALSE
;
1753 /* Read the translation file, if possible. */
1754 if(translation_file
!= NULL
)
1761 file
= Open(translation_file
,MODE_OLDFILE
);
1764 if(Read(file
,A2M
,256) != 256 ||
1765 Read(file
,M2A
,256) != 256)
1767 msg
= "Could not read translation file";
1775 msg
= "Could not open translation file";
1781 TranslateNames
= TRUE
;
1785 UBYTE description
[100];
1787 Fault(error
,NULL
,description
,sizeof(description
));
1788 for(i
= ((int)strlen(description
)) - 1 ; i
>= 0 ; i
--)
1790 if(description
[i
] == '\n')
1791 description
[i
] = '\0';
1794 ReportError("%s '%s' (%ld, %s).",msg
,translation_file
,error
,description
);
1807 /****************************************************************************/
1810 /* Make connection to server and make a volume for it. */
1816 STRPTR opt_password
,
1817 STRPTR opt_clientname
,
1818 STRPTR opt_servername
,
1823 BOOL result
= FALSE
;
1825 STRPTR actual_volume_name
;
1826 LONG actual_volume_name_len
;
1827 UBYTE name
[MAX_FILENAME_LEN
];
1832 error
= smba_start(service
,workgroup
,username
,opt_password
,opt_clientname
,opt_servername
,opt_cachesize
,&ServerData
);
1835 StartReconnectTimer();
1839 /* Examine the volume name; make sure that it is
1842 if(volume_name
== NULL
)
1843 actual_volume_name
= device_name
;
1845 actual_volume_name
= volume_name
;
1847 actual_volume_name_len
= strlen(actual_volume_name
);
1848 if(actual_volume_name_len
> 255)
1849 actual_volume_name_len
= 255;
1851 for(i
= 0 ; i
< actual_volume_name_len
; i
++)
1853 if(actual_volume_name
[i
] == '/')
1855 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
1860 /* Lose any trailing colon characters. */
1861 for(i
= actual_volume_name_len
-1 ; i
>= 0 ; i
--)
1863 if(actual_volume_name
[i
] == ':')
1864 actual_volume_name_len
= i
;
1867 if(actual_volume_name_len
== 0)
1869 ReportError("Volume name '%s' cannot be used with AmigaDOS.",actual_volume_name
);
1873 /* Now, finally, take care of the volume name. */
1874 memcpy(name
,actual_volume_name
,actual_volume_name_len
);
1875 name
[actual_volume_name_len
] = '\0';
1877 VolumeNode
= MakeDosEntry(name
,DLT_VOLUME
);
1878 if(VolumeNode
== NULL
)
1880 ReportError("Could not create volume node.");
1884 VolumeNode
->dol_Task
= FileSystemPort
;
1885 DateStamp(&VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
);
1886 VolumeNode
->dol_misc
.dol_volume
.dol_DiskType
= ID_DOS_DISK
;
1888 /* Note: we always need the volume node to make some file
1889 * system operations safe (e.g. Lock()), but we may
1890 * not always need to make it visible.
1892 if(volume_name
!= NULL
&& VolumeNode
!= NULL
)
1894 AddDosEntry(VolumeNode
);
1895 VolumeNodeAdded
= TRUE
;
1898 /* Tell Workbench and friends to update their volume lists. */
1900 SendDiskChange(IECLASS_DISKINSERTED
);
1910 /****************************************************************************/
1913 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
1915 ConvertBString(LONG max_len
,STRPTR cstring
,APTR bstring
)
1917 #ifdef AROS_FAST_BSTR
1918 strncpy(cstring
, bstring
, max_len
);
1920 STRPTR from
= bstring
;
1927 memcpy(cstring
,from
+1,len
);
1929 cstring
[len
] = '\0';
1933 /* Convert a NUL terminated 'C' string into a BCPL string. */
1935 ConvertCString(LONG max_len
, APTR bstring
, STRPTR cstring
)
1937 LONG len
= strlen(cstring
);
1938 STRPTR to
= bstring
;
1944 memcpy(to
,cstring
,len
);
1947 /****************************************************************************/
1949 /* Build the fully qualified name of a file or directory in reference
1950 * to the name of the parent directory. This takes care of all the
1951 * special cases, such as the root directory. The result will be converted
1952 * to be in a form suitable for use with the SMB file sharing service.
1958 STRPTR
* result_ptr
,
1959 LONG
* result_size_ptr
)
1968 SHOWSTRING(parent_name
);
1971 (*result_ptr
) = NULL
;
1973 /* Throw everything left of the colon away. */
1976 for(i
= 0 ; i
< (LONG
)strlen(name
) ; i
++)
1986 /* Now, how much room is needed for the complete
1987 * path to fit into a buffer?
1991 if(parent_name
!= NULL
)
1992 len
+= strlen(parent_name
) + 1;
1995 len
+= strlen(name
) + 1;
1997 if(len
< SMB_MAXNAMELEN
)
1998 len
= SMB_MAXNAMELEN
;
2002 buffer
= AllocateMemory(size
);
2005 error
= ERROR_NO_FREE_STORE
;
2009 /* Start by filling in the path name. */
2010 if(parent_name
!= NULL
)
2012 /* Skip any excess separators. */
2013 while((*parent_name
) == SMB_PATH_SEPARATOR
)
2016 buffer
[0] = SMB_PATH_SEPARATOR
;
2017 strcpy(&buffer
[1],parent_name
);
2021 strcpy(buffer
,SMB_ROOT_DIR_NAME
);
2024 /* If there's a name to add, do just that. */
2032 buffer_len
= strlen(buffer
);
2033 name_len
= strlen(name
);
2041 /* Extract the next path name segment. */
2042 for(i
= segment_start
; i
<= name_len
; i
++)
2046 segment_len
= i
- segment_start
;
2049 else if (name
[i
] == '/')
2051 segment_len
= i
- segment_start
+ 1;
2056 /* We're finished if there are no further
2057 * path name segments to take care of.
2059 if(segment_len
== 0)
2061 buffer
[buffer_len
] = '\0';
2065 /* A single slash indicates that we need to move up
2066 * to the parent directory, if any.
2068 if(segment_len
== 1 && name
[segment_start
] == '/')
2070 /* Is this already the root directory name? */
2080 /* Skip the last path component. */
2081 for(i
= 1 ; i
<= buffer_len
; i
++)
2085 /* We just skipped the first path
2086 * component following the root
2087 * directory name. We preserve
2088 * the first character since it
2089 * refers to the root directory.
2094 else if (buffer
[buffer_len
-i
] == SMB_PATH_SEPARATOR
)
2096 /* This removes both the path separator and
2097 * the name following it.
2107 /* Add a proper separator character if
2110 if(buffer_len
> 0 && buffer
[buffer_len
-1] != SMB_PATH_SEPARATOR
)
2111 buffer
[buffer_len
++] = SMB_PATH_SEPARATOR
;
2113 /* Find out how many characters are in that name; this
2114 * excludes the terminating slash.
2116 if(name
[segment_start
+ segment_len
- 1] == '/')
2117 len
= segment_len
- 1;
2121 memcpy(&buffer
[buffer_len
],&name
[segment_start
],len
);
2125 segment_start
+= segment_len
;
2129 (*result_ptr
) = buffer
;
2130 (*result_size_ptr
) = size
;
2143 /****************************************************************************/
2147 struct FileSysStartupMsg
* fssm
,
2148 struct DosList
* device_node
,
2152 LONG cache_size
= 0;
2153 char env_workgroup_name
[17];
2154 char env_service_name
[17];
2155 char env_user_name
[64];
2156 char env_password
[64];
2158 BOOL result
= DOSTRUE
;
2163 DeviceNode
= device_node
;
2164 device_node
->dol_Task
= FileSystemPort
;
2166 memset(&args
,0,sizeof(args
));
2168 Parameters
= AllocDosObject(DOS_RDARGS
, NULL
);
2169 if(Parameters
== NULL
)
2172 ((struct DosEnvec
*)BADDR(fssm
->fssm_Environ
))->de_Control
;
2173 Parameters
->RDA_Source
.CS_Buffer
= control
;
2174 Parameters
->RDA_Source
.CS_Length
= strlen(control
);
2175 Parameters
= ReadArgs(control_template
,(IPTR
*)&args
,Parameters
);
2176 if(Parameters
== NULL
)
2181 if(args
.Workgroup
== NULL
)
2183 if(GetVar("smbfs_domain",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0 ||
2184 GetVar("smbfs_workgroup",env_workgroup_name
,sizeof(env_workgroup_name
),0) > 0)
2186 args
.Workgroup
= env_workgroup_name
;
2190 args
.Workgroup
= "WORKGROUP";
2194 if(args
.UserName
== NULL
)
2196 if(GetVar("smbfs_user",env_user_name
,sizeof(env_user_name
),0) > 0 ||
2197 GetVar("smbfs_username",env_user_name
,sizeof(env_user_name
),0) > 0)
2199 args
.UserName
= env_user_name
;
2203 if(args
.Password
== NULL
)
2205 if(GetVar("smbfs_password",env_password
,sizeof(env_password
),0) > 0)
2206 args
.Password
= env_password
;
2209 if(args
.Service
== NULL
)
2211 if(GetVar("smbfs_service",env_service_name
,sizeof(env_service_name
),0) > 0 ||
2212 GetVar("smbfs_share",env_service_name
,sizeof(env_service_name
),0) > 0)
2214 args
.Service
= env_service_name
;
2218 ReportError("Required 'SERVICE' parameter was not provided.");
2223 if(args
.CacheSize
!= NULL
)
2224 cache_size
= (*args
.CacheSize
);
2226 /* Use the default if no user name is given. */
2227 if(args
.UserName
== NULL
)
2228 args
.UserName
= "GUEST";
2230 /* Volume name defaults to share name. */
2231 if(args
.VolumeName
== NULL
)
2232 args
.VolumeName
= FilePart(args
.Service
);
2234 /* Use the default if no device or volume name is given. */
2235 if(args
.DeviceName
== NULL
&& args
.VolumeName
== NULL
)
2236 args
.DeviceName
= "SMBFS";
2238 CaseSensitive
= (BOOL
)args
.CaseSensitive
;
2239 OmitHidden
= (BOOL
)args
.OmitHidden
;
2241 /* Configure the debugging options. */
2242 if(args
.DebugLevel
!= NULL
)
2243 SETDEBUGLEVEL(*args
.DebugLevel
);
2247 D(("%s (%s)",VERS
,DATE
));
2252 args
.TimeZoneOffset
,
2254 args
.TranslationFile
))
2274 (*error_ptr
) = error
;
2280 /****************************************************************************/
2284 struct FileLock
* parent
,
2288 STRPTR full_name
= NULL
;
2289 LONG full_name_size
;
2291 BOOL cleanup
= TRUE
;
2292 struct LockNode
* ln
= NULL
;
2301 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2303 parent_name
= parent_ln
->ln_FullName
;
2310 error
= BuildFullName(parent_name
,"/",&full_name
,&full_name_size
);
2314 /* Check if we ended up having to return the parent of
2315 * the root directory. This is indicated by a NULL
2316 * name pointer and a zero error code.
2318 if(full_name
== NULL
)
2321 ln
= AllocateMemory(sizeof(*ln
));
2324 error
= ERROR_NO_FREE_STORE
;
2328 memset(ln
,0,sizeof(*ln
));
2330 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2331 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
2332 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2333 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2334 ln
->ln_FullName
= full_name
;
2336 SHOWSTRING(full_name
);
2338 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2341 error
= MapErrnoToIoErr(error
);
2345 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2346 result
= MKBADDR(&ln
->ln_FileLock
);
2348 SHOWVALUE(&ln
->ln_FileLock
);
2354 FreeMemory(full_name
);
2358 (*error_ptr
) = error
;
2364 /****************************************************************************/
2366 /* Find the lock node corresponding to a given name,
2367 * starting from node start. (if node, this one is skipped)
2369 STATIC
struct LockNode
*
2370 FindNextLockNode(STRPTR name
,struct LockNode
* last_ln
)
2372 struct LockNode
* result
= NULL
;
2373 struct LockNode
* ln
;
2374 struct LockNode
* start
;
2377 start
= (struct LockNode
*)last_ln
->ln_MinNode
.mln_Succ
;
2379 start
= (struct LockNode
*)LockList
.mlh_Head
;
2382 ln
->ln_MinNode
.mln_Succ
!= NULL
;
2383 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
2385 if(CompareNames(name
,ln
->ln_FullName
) == SAME
)
2395 /****************************************************************************/
2398 Action_DeleteObject(
2399 struct FileLock
* parent
,
2403 LONG result
= DOSFALSE
;
2404 STRPTR full_name
= NULL
;
2405 LONG full_name_size
;
2406 smba_file_t
* file
= NULL
;
2408 STRPTR full_parent_name
= NULL
;
2409 UBYTE name
[MAX_FILENAME_LEN
];
2410 struct LockNode
* ln
;
2418 error
= ERROR_DISK_WRITE_PROTECTED
;
2426 ln
= (struct LockNode
*)parent
->fl_Key
;
2428 parent_name
= ln
->ln_FullName
;
2435 ConvertBString(sizeof(name
),name
,bcpl_name
);
2436 TranslateCName(name
,A2M
);
2438 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2442 /* Trying to delete the root directory, are you kidding? */
2443 if(full_name
== NULL
)
2445 error
= ERROR_OBJECT_WRONG_TYPE
;
2449 /* We need to find this file's parent directory, so that
2450 * in case the directory contents are currently being
2451 * examined, that process is restarted.
2453 full_parent_name
= AllocateMemory(strlen(full_name
)+3);
2454 if(full_parent_name
== NULL
)
2456 error
= ERROR_NO_FREE_STORE
;
2460 strcpy(full_parent_name
,full_name
);
2462 /* Build the parent object name - Piru */
2463 if (full_parent_name
[0] != '\0')
2467 i
= strlen(full_parent_name
) - 1;
2468 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2471 for ( ; i
>= 0 ; i
--)
2473 if (full_parent_name
[i
] == SMB_PATH_SEPARATOR
)
2475 full_parent_name
[i
] = '\0';
2481 /* NOTE: Mark all locks to this object as restart, not just first
2484 while ((ln
= FindNextLockNode(full_parent_name
, ln
)) != NULL
)
2485 ln
->ln_RestartExamine
= TRUE
;
2487 ln
= FindLockNode(full_parent_name
,NULL
);
2489 ln
->ln_RestartExamine
= TRUE
;
2491 FreeMemory(full_parent_name
);
2492 full_parent_name
= NULL
;
2494 SHOWSTRING(full_name
);
2496 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
2499 error
= MapErrnoToIoErr(error
);
2503 error
= smba_getattr(file
,&st
);
2506 error
= MapErrnoToIoErr(error
);
2515 SHOWMSG("removing a directory");
2517 error
= smba_rmdir(ServerData
,full_name
);
2522 /* This is a little bit difficult to justify since
2523 * the error code may indicate a different cause,
2524 * but in practice 'EACCES' seems to be returned
2525 * if the directory to remove is not empty.
2527 if(error
== (-EACCES
))
2528 error
= ERROR_DIRECTORY_NOT_EMPTY
;
2530 error
= MapErrnoToIoErr(error
);
2537 SHOWMSG("removing a file");
2539 error
= smba_remove(ServerData
,full_name
);
2544 error
= MapErrnoToIoErr(error
);
2555 FreeMemory(full_name
);
2556 FreeMemory(full_parent_name
);
2560 (*error_ptr
) = error
;
2566 /****************************************************************************/
2570 struct FileLock
* parent
,
2575 STRPTR full_name
= NULL
;
2576 LONG full_name_size
;
2577 struct LockNode
* ln
= NULL
;
2579 STRPTR dir_name
= NULL
;
2580 smba_file_t
* dir
= NULL
;
2582 UBYTE name
[MAX_FILENAME_LEN
];
2590 error
= ERROR_DISK_WRITE_PROTECTED
;
2598 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2600 parent_name
= parent_ln
->ln_FullName
;
2607 ConvertBString(sizeof(name
),name
,bcpl_name
);
2608 TranslateCName(name
,A2M
);
2610 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2614 /* Trying to overwrite the root directory, are you kidding? */
2615 if(full_name
== NULL
)
2617 error
= ERROR_OBJECT_IN_USE
;
2621 dir_name
= AllocateMemory(strlen(full_name
)+3);
2622 if(dir_name
== NULL
)
2624 error
= ERROR_NO_FREE_STORE
;
2628 strcpy(dir_name
,full_name
);
2630 for(i
= strlen(dir_name
)-1 ; i
>= 0 ; i
--)
2632 if(dir_name
[i
] == SMB_PATH_SEPARATOR
)
2636 memmove(&dir_name
[1],&dir_name
[0],strlen(dir_name
)+1);
2642 base_name
= &dir_name
[i
+1];
2647 ln
= AllocateMemory(sizeof(*ln
));
2650 error
= ERROR_NO_FREE_STORE
;
2654 memset(ln
,0,sizeof(*ln
));
2656 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2657 ln
->ln_FileLock
.fl_Access
= EXCLUSIVE_LOCK
;
2658 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2659 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2660 ln
->ln_FullName
= full_name
;
2662 error
= smba_open(ServerData
,dir_name
,strlen(full_name
)+3,&dir
);
2665 error
= MapErrnoToIoErr(error
);
2669 error
= smba_mkdir(dir
,base_name
);
2672 error
= MapErrnoToIoErr(error
);
2679 SHOWSTRING(full_name
);
2681 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2684 error
= MapErrnoToIoErr(error
);
2688 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2689 result
= MKBADDR(&ln
->ln_FileLock
);
2690 SHOWVALUE(&ln
->ln_FileLock
);
2697 FreeMemory(dir_name
);
2701 FreeMemory(full_name
);
2705 (*error_ptr
) = error
;
2711 /****************************************************************************/
2714 Action_LocateObject(
2715 struct FileLock
* parent
,
2721 STRPTR full_name
= NULL
;
2722 LONG full_name_size
;
2723 struct LockNode
* ln
= NULL
;
2725 UBYTE name
[MAX_FILENAME_LEN
];
2734 struct LockNode
* parent_ln
= (struct LockNode
*)parent
->fl_Key
;
2736 parent_name
= parent_ln
->ln_FullName
;
2743 ConvertBString(sizeof(name
),name
,bcpl_name
);
2744 TranslateCName(name
,A2M
);
2746 if(IsReservedName(FilePart(name
)))
2748 error
= ERROR_OBJECT_NOT_FOUND
;
2752 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
2756 /* Trying to get a lock on the root directory's parent?
2759 if(full_name
== NULL
)
2761 error
= ERROR_OBJECT_NOT_FOUND
;
2765 ln
= AllocateMemory(sizeof(*ln
));
2768 error
= ERROR_NO_FREE_STORE
;
2772 memset(ln
,0,sizeof(*ln
));
2774 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2775 ln
->ln_FileLock
.fl_Access
= (mode
!= EXCLUSIVE_LOCK
) ? SHARED_LOCK
: EXCLUSIVE_LOCK
;
2776 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2777 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2778 ln
->ln_FullName
= full_name
;
2780 error
= CheckAccessModeCollision(full_name
,ln
->ln_FileLock
.fl_Access
);
2784 SHOWSTRING(full_name
);
2786 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2789 error
= MapErrnoToIoErr(error
);
2793 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2794 result
= MKBADDR(&ln
->ln_FileLock
);
2795 SHOWVALUE(&ln
->ln_FileLock
);
2801 FreeMemory(full_name
);
2805 (*error_ptr
) = error
;
2811 /****************************************************************************/
2815 struct FileLock
* lock
,
2819 STRPTR full_name
= NULL
;
2820 LONG full_name_size
;
2821 struct LockNode
* ln
= NULL
;
2830 if(lock
!= NULL
&& lock
->fl_Access
!= SHARED_LOCK
)
2832 SHOWMSG("cannot duplicate exclusive lock");
2833 error
= ERROR_OBJECT_IN_USE
;
2837 ln
= AllocateMemory(sizeof(*ln
));
2840 error
= ERROR_NO_FREE_STORE
;
2844 memset(ln
,0,sizeof(*ln
));
2848 struct LockNode
* source
= (struct LockNode
*)lock
->fl_Key
;
2850 source_name
= source
->ln_FullName
;
2851 source_mode
= source
->ln_FileLock
.fl_Access
;
2855 source_name
= SMB_ROOT_DIR_NAME
;
2856 source_mode
= SHARED_LOCK
;
2859 full_name_size
= strlen(source_name
)+3;
2860 if(full_name_size
< SMB_MAXNAMELEN
+1)
2861 full_name_size
= SMB_MAXNAMELEN
+1;
2863 full_name
= AllocateMemory(full_name_size
);
2864 if(full_name
== NULL
)
2866 error
= ERROR_NO_FREE_STORE
;
2870 strcpy(full_name
,source_name
);
2872 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
2873 ln
->ln_FileLock
.fl_Access
= source_mode
;
2874 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
2875 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
2876 ln
->ln_FullName
= full_name
;
2878 SHOWSTRING(full_name
);
2880 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
2883 error
= MapErrnoToIoErr(error
);
2887 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
2888 result
= MKBADDR(&ln
->ln_FileLock
);
2889 SHOWVALUE(&ln
->ln_FileLock
);
2895 FreeMemory(full_name
);
2899 (*error_ptr
) = error
;
2905 /****************************************************************************/
2909 struct FileLock
* lock
,
2912 LONG result
= DOSTRUE
;
2913 struct LockNode
* ln
;
2923 ln
= (struct LockNode
*)lock
->fl_Key
;
2925 Remove((struct Node
*)ln
);
2926 smba_close(ln
->ln_File
);
2927 FreeMemory(ln
->ln_FullName
);
2932 (*error_ptr
) = error
;
2938 /****************************************************************************/
2942 struct FileLock
* lock1
,
2943 struct FileLock
* lock2
,
2946 LONG result
= DOSFALSE
;
2958 struct LockNode
* ln
= (struct LockNode
*)lock1
->fl_Key
;
2960 name1
= ln
->ln_FullName
;
2964 name1
= SMB_ROOT_DIR_NAME
;
2969 struct LockNode
* ln
= (struct LockNode
*)lock2
->fl_Key
;
2971 name2
= ln
->ln_FullName
;
2975 name2
= SMB_ROOT_DIR_NAME
;
2981 if(Stricmp(name1
,name2
) == SAME
)
2984 (*error_ptr
) = error
;
2990 /****************************************************************************/
2994 struct FileLock
* parent
,
2999 LONG result
= DOSFALSE
;
3000 STRPTR full_name
= NULL
;
3001 LONG full_name_size
;
3002 smba_file_t
* file
= NULL
;
3004 UBYTE name
[MAX_FILENAME_LEN
];
3012 error
= ERROR_DISK_WRITE_PROTECTED
;
3020 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
3022 parent_name
= ln
->ln_FullName
;
3029 ConvertBString(sizeof(name
),name
,bcpl_name
);
3030 TranslateCName(name
,A2M
);
3032 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
3036 /* Trying to change the protection bits of the root
3037 * directory, are you kidding?
3039 if(full_name
== NULL
)
3041 error
= ERROR_OBJECT_WRONG_TYPE
;
3045 SHOWSTRING(full_name
);
3047 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
3050 error
= MapErrnoToIoErr(error
);
3054 memset(&st
,0,sizeof(st
));
3056 mask
^= FIBF_READ
| FIBF_WRITE
| FIBF_EXECUTE
| FIBF_DELETE
;
3063 if((mask
& (FIBF_WRITE
|FIBF_DELETE
)) != (FIBF_WRITE
|FIBF_DELETE
))
3065 SHOWMSG("write protection enabled");
3070 SHOWMSG("write protection disabled");
3073 /* Careful: the 'archive' attribute has exactly the opposite
3074 * meaning in the Amiga and the SMB worlds.
3076 st
.is_archive
= ((mask
& FIBF_ARCHIVE
) == 0);
3078 /* The 'system' attribute is associated with the 'pure' bit for now. */
3079 st
.is_system
= ((mask
& FIBF_PURE
) != 0);
3081 error
= smba_setattr(file
,&st
);
3084 error
= MapErrnoToIoErr(error
);
3092 FreeMemory(full_name
);
3096 (*error_ptr
) = error
;
3102 /****************************************************************************/
3105 Action_RenameObject(
3106 struct FileLock
* source_lock
,
3107 APTR source_bcpl_name
,
3108 struct FileLock
* destination_lock
,
3109 APTR destination_bcpl_name
,
3112 struct LockNode
* ln
;
3113 LONG result
= DOSFALSE
;
3114 STRPTR full_source_name
= NULL
;
3115 LONG full_source_name_size
;
3116 STRPTR full_destination_name
= NULL
;
3117 LONG full_destination_name_size
;
3118 UBYTE name
[MAX_FILENAME_LEN
];
3126 error
= ERROR_DISK_WRITE_PROTECTED
;
3130 SHOWVALUE(source_lock
);
3131 SHOWVALUE(destination_lock
);
3133 if(source_lock
!= NULL
)
3135 ln
= (struct LockNode
*)source_lock
->fl_Key
;
3137 parent_name
= ln
->ln_FullName
;
3144 ConvertBString(sizeof(name
),name
,source_bcpl_name
);
3145 TranslateCName(name
,A2M
);
3147 error
= BuildFullName(parent_name
,name
,&full_source_name
,&full_source_name_size
);
3151 /* Trying to rename the root directory, are you kidding? */
3152 if(full_source_name
== NULL
)
3154 error
= ERROR_OBJECT_IN_USE
;
3158 if(destination_lock
!= NULL
)
3160 ln
= (struct LockNode
*)destination_lock
->fl_Key
;
3162 parent_name
= ln
->ln_FullName
;
3169 ConvertBString(sizeof(name
),name
,destination_bcpl_name
);
3170 TranslateCName(name
,A2M
);
3172 error
= BuildFullName(parent_name
,name
,&full_destination_name
,&full_destination_name_size
);
3176 /* Trying to rename the root directory, are you kidding? */
3177 if(full_destination_name
== NULL
)
3179 error
= ERROR_OBJECT_IN_USE
;
3183 error
= NameAlreadyInUse(full_source_name
);
3187 error
= NameAlreadyInUse(full_destination_name
);
3191 SHOWSTRING(full_source_name
);
3192 SHOWSTRING(full_destination_name
);
3194 error
= smba_rename(ServerData
,full_source_name
,full_destination_name
);
3197 error
= MapErrnoToIoErr(error
);
3205 FreeMemory(full_source_name
);
3206 FreeMemory(full_destination_name
);
3208 (*error_ptr
) = error
;
3214 /****************************************************************************/
3218 struct InfoData
* id
,
3221 LONG result
= DOSTRUE
;
3224 long num_blocks_free
;
3229 memset(id
,0,sizeof(*id
));
3232 id
->id_DiskState
= ID_WRITE_PROTECTED
;
3234 id
->id_DiskState
= ID_VALIDATED
;
3236 error
= smba_statfs(ServerData
,&block_size
,&num_blocks
,&num_blocks_free
);
3239 SHOWMSG("got the disk data");
3240 SHOWVALUE(block_size
);
3241 SHOWVALUE(num_blocks
);
3242 SHOWVALUE(num_blocks_free
);
3247 if(block_size
< 512)
3249 num_blocks
/= (512 / block_size
);
3250 num_blocks_free
/= (512 / block_size
);
3252 else if (block_size
> 512)
3254 num_blocks
*= (block_size
/ 512);
3255 num_blocks_free
*= (block_size
/ 512);
3258 id
->id_NumBlocks
= num_blocks
;
3259 id
->id_NumBlocksUsed
= num_blocks
- num_blocks_free
;
3260 id
->id_BytesPerBlock
= 512;
3261 id
->id_DiskType
= ID_DOS_DISK
;
3262 id
->id_VolumeNode
= MKBADDR(VolumeNode
);
3263 id
->id_InUse
= NOT (IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
));
3265 if(id
->id_NumBlocks
== 0)
3266 id
->id_NumBlocks
= 1;
3268 if(id
->id_NumBlocksUsed
== 0)
3269 id
->id_NumBlocksUsed
= 1;
3273 SHOWMSG("could not get any disk data");
3275 id
->id_NumBlocks
= 1;
3276 id
->id_NumBlocksUsed
= 1;
3277 id
->id_BytesPerBlock
= 512;
3278 id
->id_DiskType
= ID_NO_DISK_PRESENT
;
3280 error
= MapErrnoToIoErr(error
);
3284 SHOWVALUE(id
->id_NumBlocks
);
3285 SHOWVALUE(id
->id_NumBlocksUsed
);
3286 SHOWVALUE(id
->id_BytesPerBlock
);
3287 SHOWVALUE(id
->id_DiskType
);
3288 SHOWVALUE(id
->id_VolumeNode
);
3289 SHOWVALUE(id
->id_InUse
);
3291 (*error_ptr
) = error
;
3299 struct FileLock
* lock
,
3300 struct InfoData
* id
,
3309 if(lock
== NULL
|| lock
->fl_Volume
!= MKBADDR(VolumeNode
))
3311 SHOWMSG("volume node does not match");
3315 (*error_ptr
) = ERROR_NO_DISK
;
3319 result
= Action_DiskInfo(id
,error_ptr
);
3326 /****************************************************************************/
3329 Action_ExamineObject(
3330 struct FileLock
* lock
,
3331 struct FileInfoBlock
* fib
,
3334 LONG result
= DOSFALSE
;
3341 memset(fib
,0,sizeof(*fib
));
3345 #if !defined(__AROS__)
3346 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3347 LONG len
= volume_name
[0];
3349 memcpy(fib
->fib_FileName
+1, volume_name
+ 1, len
);
3350 fib
->fib_FileName
[0] = len
;
3352 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3353 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3355 memcpy(fib
->fib_FileName
+ 1, volume_name
, len
);
3356 fib
->fib_FileName
[0] = len
;
3358 SHOWMSG("ZERO root lock");
3360 fib
->fib_DirEntryType
= ST_ROOT
;
3361 fib
->fib_EntryType
= ST_ROOT
;
3362 fib
->fib_NumBlocks
= 1;
3363 fib
->fib_Date
= VolumeNode
->dol_misc
.dol_volume
.dol_VolumeDate
;
3364 fib
->fib_DiskKey
= -1;
3365 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3366 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3370 struct LockNode
* ln
= (struct LockNode
*)lock
->fl_Key
;
3374 error
= smba_getattr(ln
->ln_File
,&st
);
3377 SHOWMSG("information not available");
3379 error
= MapErrnoToIoErr(error
);
3383 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
3387 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
3388 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
3389 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
3391 SHOWSTRING(ln
->ln_FullName
);
3393 if(strcmp(ln
->ln_FullName
,SMB_ROOT_DIR_NAME
) == SAME
)
3395 #if !defined(__AROS__)
3396 STRPTR volume_name
= BADDR(VolumeNode
->dol_Name
);
3397 LONG len
= volume_name
[0];
3399 memcpy(fib
->fib_FileName
+1, volume_name
+ 1, len
);
3400 fib
->fib_FileName
[0] = len
;
3402 STRPTR volume_name
= AROS_BSTR_ADDR(VolumeNode
->dol_Name
);
3403 LONG len
= AROS_BSTR_strlen(VolumeNode
->dol_Name
);
3405 memcpy(fib
->fib_FileName
+ 1, volume_name
, len
);
3406 fib
->fib_FileName
[0] = len
;
3408 SHOWMSG("root lock");
3410 fib
->fib_DirEntryType
= ST_ROOT
;
3411 fib
->fib_EntryType
= ST_ROOT
;
3412 fib
->fib_NumBlocks
= 1;
3413 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3414 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3421 name
= ln
->ln_FullName
;
3422 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
3424 if(name
[i
] == SMB_PATH_SEPARATOR
)
3431 /* Just checking: will the name fit? */
3432 if(strlen(name
) >= sizeof(fib
->fib_FileName
))
3434 error
= ERROR_INVALID_COMPONENT_NAME
;
3438 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
3439 TranslateBName(fib
->fib_FileName
,M2A
);
3441 fib
->fib_DirEntryType
= st
.is_dir
? ST_USERDIR
: ST_FILE
;
3442 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
3443 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
3444 fib
->fib_Size
= st
.size
;
3445 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3446 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3449 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
3451 /* Careful: the 'archive' attribute has exactly the opposite
3452 * meaning in the Amiga and the SMB worlds.
3454 if(NOT st
.is_archive
)
3455 fib
->fib_Protection
|= FIBF_ARCHIVE
;
3458 fib
->fib_Protection
|= FIBF_PURE
;
3461 fib
->fib_DiskKey
= -1;
3467 D(("fib->fib_FileName = \"%b\"",MKBADDR(fib
->fib_FileName
)));
3468 SHOWVALUE(fib
->fib_DirEntryType
);
3469 SHOWVALUE(fib
->fib_NumBlocks
);
3470 SHOWVALUE(fib
->fib_Size
);
3471 SHOWVALUE(fib
->fib_Date
.ds_Days
);
3472 SHOWVALUE(fib
->fib_Date
.ds_Minute
);
3473 SHOWVALUE(fib
->fib_Date
.ds_Tick
);
3474 SHOWVALUE(fib
->fib_DiskKey
);
3478 (*error_ptr
) = error
;
3484 /****************************************************************************/
3487 NameIsAcceptable(STRPTR name
,LONG max_len
)
3489 BOOL result
= FALSE
;
3492 /* This takes care of "." and "..". */
3493 if(name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
3496 /* Now for embedded '/', ':' and '\' characters and
3497 * names that just don't want to fit.
3499 while((c
= (*name
++)) != '\0')
3502 if(max_len
== 0 || c
== '/' || c
== ':' || c
== SMB_PATH_SEPARATOR
)
3513 /****************************************************************************/
3516 dir_scan_callback_func_exnext(
3517 struct FileInfoBlock
* fib
,
3529 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
3530 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
3531 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
3533 /* Skip file and drawer names that we wouldn't be
3534 * able to handle in the first place.
3536 if(NameIsAcceptable((STRPTR
)name
,sizeof(fib
->fib_FileName
)) && NOT (st
->is_hidden
&& OmitHidden
))
3540 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
3541 TranslateBName(fib
->fib_FileName
,M2A
);
3543 fib
->fib_DirEntryType
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
3544 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
3545 fib
->fib_NumBlocks
= (st
->size
+ 511) / 512;
3546 fib
->fib_Size
= st
->size
;
3547 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3548 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3551 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
3553 /* Careful: the 'archive' attribute has exactly the opposite
3554 * meaning in the Amiga and the SMB worlds.
3556 if(NOT st
->is_archive
)
3557 fib
->fib_Protection
|= FIBF_ARCHIVE
;
3560 fib
->fib_Protection
|= FIBF_PURE
;
3562 seconds
= st
->mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
3566 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
3567 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
3568 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
3577 fib
->fib_DiskKey
= eof
? -1 : nextpos
;
3585 struct FileLock
* lock
,
3586 struct FileInfoBlock
* fib
,
3589 struct LockNode
* ln
;
3590 LONG result
= DOSFALSE
;
3599 if(fib
->fib_DiskKey
== -1)
3601 SHOWMSG("scanning finished.");
3602 error
= ERROR_NO_MORE_ENTRIES
;
3608 SHOWMSG("invalid lock");
3609 error
= ERROR_INVALID_LOCK
;
3613 offset
= fib
->fib_DiskKey
;
3615 ln
= (struct LockNode
*)lock
->fl_Key
;
3617 /* Check if we should restart scanning the directory
3618 * contents. This is tricky at best and may produce
3619 * irritating results :(
3621 if(ln
->ln_RestartExamine
)
3625 ln
->ln_RestartExamine
= FALSE
;
3628 memset(fib
,0,sizeof(*fib
));
3630 SHOWMSG("calling 'smba_readdir'");
3633 count
= smba_readdir(ln
->ln_File
,offset
,fib
,(smba_callback_t
)dir_scan_callback_func_exnext
);
3637 if(count
== 0 || fib
->fib_FileName
[0] == '\0')
3639 SHOWMSG("nothing to be read");
3640 fib
->fib_DiskKey
= -1;
3642 error
= ERROR_NO_MORE_ENTRIES
;
3645 else if (count
== (-EIO
))
3647 SHOWMSG("ouch! directory read error");
3648 fib
->fib_DiskKey
= -1;
3650 error
= ERROR_NO_DEFAULT_DIR
;
3655 SHOWMSG("error whilst scanning");
3657 fib
->fib_DiskKey
= -1;
3659 error
= MapErrnoToIoErr(count
);
3667 (*error_ptr
) = error
;
3673 /****************************************************************************/
3677 struct ExAllData
* ec_Last
;
3678 struct ExAllData
* ec_Next
;
3681 struct ExAllControl
* ec_Control
;
3684 BOOL ec_FirstAttempt
;
3688 dir_scan_callback_func_exall(
3689 struct ExAllContext
* ec
,
3701 D((" is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
3702 st
->is_dir
,st
->is_wp
,st
->is_hidden
,st
->size
));
3703 D((" nextpos=%ld eof=%ld",nextpos
,eof
));
3705 /* Skip file and drawer names that we wouldn't be
3706 * able to handle in the first place.
3708 if(NameIsAcceptable((STRPTR
)name
,MAX_FILENAME_LEN
) && NOT (st
->is_hidden
&& OmitHidden
))
3710 struct ExAllData
* ed
;
3712 ULONG type
= ec
->ec_Type
;
3715 size
= (ec
->ec_MinSize
+ strlen(name
)+1 + 3) & ~3UL;
3717 if(size
> ec
->ec_BytesLeft
)
3719 D(("size %ld > ec->ec_BytesLeft %ld",size
,ec
->ec_BytesLeft
));
3721 /* If this is the first directory entry,
3722 * stop the entire process before it has
3725 if(ec
->ec_FirstAttempt
)
3727 SHOWMSG("this was the first read attempt.");
3728 ec
->ec_Control
->eac_Entries
= 0;
3729 ec
->ec_Error
= ERROR_NO_FREE_STORE
;
3733 SHOWMSG("try again");
3744 ed
->ed_Name
= (STRPTR
)(((IPTR
)ed
) + ec
->ec_MinSize
);
3745 strcpy(ed
->ed_Name
,name
);
3747 TranslateCName(ed
->ed_Name
,M2A
);
3750 ed
->ed_Type
= st
->is_dir
? ST_USERDIR
: ST_FILE
;
3753 ed
->ed_Size
= st
->size
;
3755 if(type
>= ED_PROTECTION
)
3757 ed
->ed_Prot
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
3758 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
3761 ed
->ed_Prot
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
3763 /* Careful: the 'archive' attribute has exactly the opposite
3764 * meaning in the Amiga and the SMB worlds.
3766 if(NOT st
->is_archive
)
3767 ed
->ed_Prot
|= FIBF_ARCHIVE
;
3770 ed
->ed_Prot
|= FIBF_PURE
;
3777 seconds
= st
->mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
3781 ed
->ed_Days
= (seconds
/ (24 * 60 * 60));
3782 ed
->ed_Mins
= (seconds
% (24 * 60 * 60)) / 60;
3783 ed
->ed_Ticks
= (seconds
% 60) * TICKS_PER_SECOND
;
3786 if(type
>= ED_COMMENT
)
3787 ed
->ed_Comment
= "";
3789 if(type
>= ED_OWNER
)
3790 ed
->ed_OwnerUID
= ed
->ed_OwnerGID
= 0;
3794 if(ec
->ec_Control
->eac_MatchString
!= NULL
)
3796 SHOWMSG("checking against match string");
3797 if(NOT
MatchPatternNoCase(ec
->ec_Control
->eac_MatchString
,ed
->ed_Name
))
3799 SHOWMSG("does not match");
3804 if(take_it
&& ec
->ec_Control
->eac_MatchFunc
!= NULL
)
3806 SHOWMSG("calling match func");
3808 /* NOTE: the order of the parameters passed to the match hook
3809 * function can be somewhat confusing. For standard
3810 * hook functions, the order of the parameters and the
3811 * registers they go into is hook=A0, object=A2,
3812 * message=A1. However, the documentation for the 'ExAll()'
3813 * function always lists them in ascending order, that is
3814 * hook=A0, message=A1, object=A2, which can lead to
3815 * quite some confusion and strange errors.
3817 if(NOT
CallHookPkt(ec
->ec_Control
->eac_MatchFunc
,&type
,ed
))
3819 SHOWMSG("does not match");
3826 SHOWMSG("registering new entry");
3828 if(ec
->ec_Last
!= NULL
)
3829 ec
->ec_Last
->ed_Next
= ed
;
3832 ec
->ec_Next
= (struct ExAllData
*)(((IPTR
)ed
) + size
);
3833 ec
->ec_BytesLeft
-= size
;
3834 ec
->ec_Control
->eac_Entries
++;
3836 SHOWVALUE(ec
->ec_Last
->ed_Next
);
3837 SHOWVALUE(ed
->ed_Name
);
3838 SHOWVALUE(ed
->ed_Comment
);
3842 ec
->ec_Control
->eac_LastKey
= (ULONG
)(eof
? -1 : nextpos
);
3846 ec
->ec_FirstAttempt
= FALSE
;
3854 struct FileLock
* lock
,
3855 struct ExAllData
* ed
,
3858 struct ExAllControl
* eac
,
3861 struct ExAllContext ec
;
3862 struct LockNode
* ln
;
3863 LONG result
= DOSFALSE
;
3872 SHOWVALUE(eac
->eac_LastKey
);
3874 eac
->eac_Entries
= 0;
3876 if(size
< sizeof(ed
->ed_Next
))
3878 SHOWMSG("buffer is far too short.");
3879 error
= ERROR_NO_FREE_STORE
;
3885 if(eac
->eac_LastKey
== (ULONG
)-1)
3887 SHOWMSG("scanning finished.");
3888 error
= ERROR_NO_MORE_ENTRIES
;
3894 SHOWMSG("invalid lock");
3895 error
= ERROR_INVALID_LOCK
;
3899 if(type
< ED_NAME
|| type
> ED_OWNER
)
3901 D(("type %ld not supported",type
));
3902 error
= ERROR_BAD_NUMBER
;
3908 memset(&ec
,0,sizeof(ec
));
3911 ec
.ec_BytesLeft
= size
;
3912 ec
.ec_Control
= eac
;
3914 ec
.ec_Error
= ERROR_NO_MORE_ENTRIES
;
3915 ec
.ec_FirstAttempt
= TRUE
;
3921 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Type
);
3926 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Size
);
3931 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Prot
);
3936 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Days
);
3941 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_Comment
);
3946 ec
.ec_MinSize
= offsetof(struct ExAllData
,ed_OwnerUID
);
3951 ec
.ec_MinSize
= sizeof(struct ExAllData
);
3955 SHOWVALUE(ec
.ec_MinSize
);
3957 offset
= eac
->eac_LastKey
;
3959 ln
= (struct LockNode
*)lock
->fl_Key
;
3961 /* Check if we should restart scanning the directory
3962 * contents. This is tricky at best and may produce
3963 * irritating results :(
3965 if(ln
->ln_RestartExamine
)
3969 ln
->ln_RestartExamine
= FALSE
;
3976 SHOWMSG("first invocation");
3978 SHOWMSG("getting file attributes");
3979 error
= smba_getattr(ln
->ln_File
,&st
);
3982 SHOWMSG("didn't work");
3983 error
= MapErrnoToIoErr(error
);
3984 eac
->eac_LastKey
= (ULONG
)-1;
3990 SHOWMSG("lock does not refer to a directory");
3991 error
= ERROR_OBJECT_WRONG_TYPE
;
3992 eac
->eac_LastKey
= (ULONG
)-1;
3997 SHOWMSG("calling 'smba_readdir'");
4000 count
= smba_readdir(ln
->ln_File
,offset
,&ec
,(smba_callback_t
)dir_scan_callback_func_exall
);
4004 if(count
== 0 || eac
->eac_Entries
== 0)
4006 SHOWMSG("nothing to be read");
4007 if(ec
.ec_Error
!= OK
)
4009 SHOWMSG("flagging an error");
4010 SHOWVALUE(ec
.ec_Error
);
4011 eac
->eac_LastKey
= (ULONG
)-1;
4012 error
= ec
.ec_Error
;
4017 else if (count
== (-EIO
))
4019 SHOWMSG("ouch! directory read error");
4020 eac
->eac_LastKey
= (ULONG
)-1;
4022 error
= ERROR_NO_DEFAULT_DIR
;
4027 SHOWMSG("error whilst scanning");
4028 eac
->eac_LastKey
= (ULONG
)-1;
4030 error
= MapErrnoToIoErr(count
);
4041 SHOWVALUE(eac
->eac_Entries
);
4045 SHOWSTRING(ed
->ed_Name
);
4052 (*error_ptr
) = error
;
4058 /****************************************************************************/
4063 struct FileHandle
* fh
,
4064 struct FileLock
* parent
,
4068 LONG result
= DOSFALSE
;
4069 STRPTR parent_path
= NULL
;
4070 STRPTR full_name
= NULL
;
4071 LONG full_name_size
;
4072 struct FileNode
* fn
= NULL
;
4074 UBYTE name
[MAX_FILENAME_LEN
];
4075 BOOL file_exists
= FALSE
;
4076 BOOL create_new_file
;
4077 smba_file_t
* file
= NULL
;
4085 case ACTION_FINDINPUT
:
4086 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name
)));
4089 case ACTION_FINDOUTPUT
:
4090 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name
)));
4093 case ACTION_FINDUPDATE
:
4094 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name
)));
4102 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
4104 parent_name
= ln
->ln_FullName
;
4111 ConvertBString(sizeof(name
),name
,bcpl_name
);
4112 TranslateCName(name
,A2M
);
4114 if(IsReservedName(FilePart(name
)))
4116 error
= ERROR_OBJECT_NOT_FOUND
;
4120 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
4124 /* Trying to open the root directory? */
4125 if(full_name
== NULL
)
4127 error
= ERROR_OBJECT_WRONG_TYPE
;
4131 fn
= AllocateMemory(sizeof(*fn
));
4134 error
= ERROR_NO_FREE_STORE
;
4138 memset(fn
,0,sizeof(*fn
));
4141 fn
->fn_FullName
= full_name
;
4142 fn
->fn_Mode
= (action
== ACTION_FINDOUTPUT
) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
4144 error
= CheckAccessModeCollision(full_name
,fn
->fn_Mode
);
4148 SHOWSTRING(full_name
);
4150 if(smba_open(ServerData
,full_name
,full_name_size
,&file
) == OK
&&
4151 smba_getattr(file
,&st
) == OK
)
4156 error
= ERROR_OBJECT_WRONG_TYPE
;
4163 if(action
== ACTION_FINDOUTPUT
)
4165 /* Definitely create a new file. */
4166 create_new_file
= TRUE
;
4168 else if (action
== ACTION_FINDINPUT
)
4170 /* Open an existing file for reading. */
4171 create_new_file
= FALSE
;
4173 else if (action
== ACTION_FINDUPDATE
)
4177 /* File apparently opens Ok and information on it
4178 * is available, don't try to replace it.
4180 create_new_file
= FALSE
;
4184 /* We try to ignore the error here and assume
4185 * that the remainder of the file opening
4186 * procedure will produce a useful error
4187 * report. In the mean time, assume that the
4188 * file needs to be created.
4190 create_new_file
= TRUE
;
4196 error
= ERROR_ACTION_NOT_KNOWN
;
4200 /* Create a new file? */
4209 error
= ERROR_DISK_WRITE_PROTECTED
;
4213 parent_path
= AllocateMemory(strlen(full_name
)+3);
4214 if(parent_path
== NULL
)
4216 error
= ERROR_NO_FREE_STORE
;
4220 strcpy(parent_path
,full_name
);
4222 for(i
= strlen(parent_path
)-1 ; i
>= 0 ; i
--)
4224 if(parent_path
[i
] == SMB_PATH_SEPARATOR
)
4228 memmove(&parent_path
[1],&parent_path
[0],strlen(parent_path
)+1);
4232 parent_path
[i
] = '\0';
4234 base_name
= &parent_path
[i
+1];
4239 SHOWMSG("creating a file; finding parent path first");
4240 SHOWSTRING(parent_path
);
4242 error
= smba_open(ServerData
,parent_path
,strlen(full_name
)+3,&dir
);
4245 error
= MapErrnoToIoErr(error
);
4249 /* Only one attribute counts: the file should not be write protected. */
4250 memset(&st
,0,sizeof(st
));
4252 SHOWMSG("now trying to create the file");
4253 SHOWSTRING(base_name
);
4255 error
= smba_create(dir
,base_name
,&st
);
4258 SHOWMSG("didn't work.");
4262 error
= MapErrnoToIoErr(error
);
4274 /* Now for the remainder... */
4275 error
= smba_open(ServerData
,full_name
,full_name_size
,&fn
->fn_File
);
4278 error
= MapErrnoToIoErr(error
);
4282 fh
->fh_Arg1
= (IPTR
)fn
;
4284 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
4289 if(result
== DOSFALSE
)
4291 FreeMemory(full_name
);
4295 FreeMemory(parent_path
);
4297 (*error_ptr
) = error
;
4303 /****************************************************************************/
4307 struct FileNode
* fn
,
4319 result
= smba_read(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4322 error
= MapErrnoToIoErr(result
);
4327 fn
->fn_Offset
+= result
;
4332 (*error_ptr
) = error
;
4338 /****************************************************************************/
4342 struct FileNode
* fn
,
4347 LONG result
= DOSFALSE
;
4354 error
= ERROR_DISK_WRITE_PROTECTED
;
4360 result
= smba_write(fn
->fn_File
,mem
,length
,fn
->fn_Offset
);
4363 error
= MapErrnoToIoErr(result
);
4368 fn
->fn_Offset
+= result
;
4373 (*error_ptr
) = error
;
4379 /****************************************************************************/
4383 struct FileNode
* fn
,
4386 Remove((struct Node
*)fn
);
4388 smba_close(fn
->fn_File
);
4389 FreeMemory(fn
->fn_FullName
);
4396 /****************************************************************************/
4400 struct FileNode
* fn
,
4405 LONG previous_position
= fn
->fn_Offset
;
4412 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4417 case OFFSET_BEGINNING
:
4422 case OFFSET_CURRENT
:
4434 error
= ERROR_ACTION_NOT_KNOWN
;
4438 error
= smba_seek (fn
->fn_File
, position
, mode
, (off_t
*) &offset
);
4441 error
= MapErrnoToIoErr(error
);
4447 /* olsen: This is the original implementation. */
4452 error
= smba_getattr(fn
->fn_File
,&st
);
4455 error
= MapErrnoToIoErr(error
);
4459 offset
= fn
->fn_Offset
;
4463 case OFFSET_BEGINNING
:
4468 case OFFSET_CURRENT
:
4475 offset
= st
.size
+ position
;
4480 error
= ERROR_ACTION_NOT_KNOWN
;
4484 if(offset
< 0 || offset
> st
.size
)
4486 error
= ERROR_SEEK_ERROR
;
4492 /* olsen: This is a mix of the two above. First we calculate the absolute
4493 * position, then seek to that position. The SMB server is supposed
4494 * to do its housekeeping before the position is changed. I wish this
4495 * worked differently, but it seems we've got the best of both worlds
4504 case OFFSET_BEGINNING
:
4509 case OFFSET_CURRENT
:
4511 offset
= fn
->fn_Offset
+ position
;
4516 error
= smba_getattr(fn
->fn_File
,&st
);
4519 error
= MapErrnoToIoErr(error
);
4523 offset
= st
.size
+ position
;
4528 error
= ERROR_ACTION_NOT_KNOWN
;
4534 error
= ERROR_SEEK_ERROR
;
4538 error
= smba_seek (fn
->fn_File
, offset
, 0, (off_t
*) &offset
);
4541 error
= MapErrnoToIoErr(error
);
4549 fn
->fn_Offset
= offset
;
4551 result
= previous_position
;
4555 (*error_ptr
) = error
;
4561 /****************************************************************************/
4565 struct FileNode
* fn
,
4579 error
= ERROR_DISK_WRITE_PROTECTED
;
4583 error
= smba_getattr(fn
->fn_File
,&st
);
4586 error
= MapErrnoToIoErr(error
);
4590 offset
= fn
->fn_Offset
;
4594 case OFFSET_BEGINNING
:
4599 case OFFSET_CURRENT
:
4606 offset
= st
.size
+ position
;
4611 error
= ERROR_ACTION_NOT_KNOWN
;
4617 error
= ERROR_SEEK_ERROR
;
4626 error
= smba_setattr(fn
->fn_File
,&st
);
4629 error
= MapErrnoToIoErr(error
);
4633 if(fn
->fn_Offset
> offset
)
4634 fn
->fn_Offset
= offset
;
4640 (*error_ptr
) = error
;
4646 /****************************************************************************/
4650 struct FileLock
* parent
,
4652 struct DateStamp
* ds
,
4655 LONG result
= DOSFALSE
;
4656 STRPTR full_name
= NULL
;
4657 LONG full_name_size
;
4658 smba_file_t
* file
= NULL
;
4660 UBYTE name
[MAX_FILENAME_LEN
];
4669 error
= ERROR_DISK_WRITE_PROTECTED
;
4677 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
4679 parent_name
= ln
->ln_FullName
;
4686 ConvertBString(sizeof(name
),name
,bcpl_name
);
4687 TranslateCName(name
,A2M
);
4689 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
4693 /* Trying to change the date of the root directory? */
4694 if(full_name
== NULL
)
4696 error
= ERROR_OBJECT_IN_USE
;
4700 SHOWSTRING(full_name
);
4702 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
4705 error
= MapErrnoToIoErr(error
);
4709 error
= smba_getattr(file
,&st
);
4712 error
= MapErrnoToIoErr(error
);
4716 seconds
= (ds
->ds_Days
* 24 * 60 + ds
->ds_Minute
) * 60 + (ds
->ds_Tick
/ TICKS_PER_SECOND
);
4720 st
.mtime
= seconds
+ UNIX_TIME_OFFSET
+ GetTimeZoneDelta();
4723 error
= smba_setattr(file
,&st
);
4726 error
= MapErrnoToIoErr(error
);
4734 FreeMemory(full_name
);
4738 (*error_ptr
) = error
;
4744 /****************************************************************************/
4748 struct FileNode
* fn
,
4749 struct FileInfoBlock
* fib
,
4752 LONG result
= DOSFALSE
;
4761 error
= smba_getattr(fn
->fn_File
,&st
);
4764 error
= MapErrnoToIoErr(error
);
4768 name
= fn
->fn_FullName
;
4769 for(i
= strlen(name
)-1 ; i
>= 0 ; i
--)
4771 if(name
[i
] == SMB_PATH_SEPARATOR
)
4778 /* Just checking: will the name fit? */
4779 if(strlen(name
) >= sizeof(fib
->fib_FileName
))
4781 error
= ERROR_INVALID_COMPONENT_NAME
;
4785 memset(fib
,0,sizeof(*fib
));
4787 ConvertCString(sizeof(fib
->fib_FileName
),fib
->fib_FileName
,name
);
4788 TranslateBName(fib
->fib_FileName
,M2A
);
4790 fib
->fib_DirEntryType
= ST_FILE
;
4791 fib
->fib_EntryType
= ST_FILE
;
4792 fib
->fib_NumBlocks
= (st
.size
+ 511) / 512;
4793 fib
->fib_Size
= st
.size
;
4794 fib
->fib_DiskKey
= -1;
4796 fib
->fib_Protection
= FIBF_OTR_READ
|FIBF_OTR_EXECUTE
|FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|
4797 FIBF_GRP_READ
|FIBF_GRP_EXECUTE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
;
4800 fib
->fib_Protection
^= (FIBF_OTR_WRITE
|FIBF_OTR_DELETE
|FIBF_GRP_WRITE
|FIBF_GRP_DELETE
|FIBF_WRITE
|FIBF_DELETE
);
4802 /* Careful: the 'archive' attribute has exactly the opposite
4803 * meaning in the Amiga and the SMB worlds.
4805 if(NOT st
.is_archive
)
4806 fib
->fib_Protection
|= FIBF_ARCHIVE
;
4809 fib
->fib_Protection
|= FIBF_PURE
;
4811 seconds
= st
.mtime
- UNIX_TIME_OFFSET
- GetTimeZoneDelta();
4815 fib
->fib_Date
.ds_Days
= (seconds
/ (24 * 60 * 60));
4816 fib
->fib_Date
.ds_Minute
= (seconds
% (24 * 60 * 60)) / 60;
4817 fib
->fib_Date
.ds_Tick
= (seconds
% 60) * TICKS_PER_SECOND
;
4823 (*error_ptr
) = error
;
4829 /****************************************************************************/
4833 struct FileNode
* fn
,
4837 struct LockNode
* ln
= NULL
;
4840 LONG full_name_size
;
4845 full_name_size
= strlen(fn
->fn_FullName
)+3;
4846 if(full_name_size
< SMB_MAXNAMELEN
+1)
4847 full_name_size
= SMB_MAXNAMELEN
+1;
4849 full_name
= AllocateMemory(full_name_size
);
4850 if(full_name
== NULL
)
4852 error
= ERROR_NO_FREE_STORE
;
4856 strcpy(full_name
,fn
->fn_FullName
);
4858 for(i
= strlen(full_name
)-1 ; i
>= 0 ; i
--)
4862 strcpy(full_name
,SMB_ROOT_DIR_NAME
);
4865 else if (full_name
[i
] == SMB_PATH_SEPARATOR
)
4867 full_name
[i
] = '\0';
4872 ln
= AllocateMemory(sizeof(*ln
));
4875 error
= ERROR_NO_FREE_STORE
;
4879 memset(ln
,0,sizeof(*ln
));
4881 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
4882 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
4883 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
4884 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
4885 ln
->ln_FullName
= full_name
;
4887 SHOWSTRING(full_name
);
4889 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
4892 error
= MapErrnoToIoErr(error
);
4896 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
4897 result
= MKBADDR(&ln
->ln_FileLock
);
4898 SHOWVALUE(&ln
->ln_FileLock
);
4905 FreeMemory(full_name
);
4908 (*error_ptr
) = error
;
4914 /****************************************************************************/
4918 struct FileNode
* fn
,
4922 struct LockNode
* ln
= NULL
;
4923 STRPTR full_name
= NULL
;
4924 LONG full_name_size
;
4929 if(fn
->fn_Mode
!= SHARED_LOCK
)
4931 error
= ERROR_OBJECT_IN_USE
;
4935 full_name_size
= strlen(fn
->fn_FullName
)+3;
4936 if(full_name_size
< SMB_MAXNAMELEN
+1)
4937 full_name_size
= SMB_MAXNAMELEN
+1;
4939 full_name
= AllocateMemory(full_name_size
);
4940 if(full_name
== NULL
)
4942 error
= ERROR_NO_FREE_STORE
;
4946 strcpy(full_name
,fn
->fn_FullName
);
4948 ln
= AllocateMemory(sizeof(*ln
));
4951 error
= ERROR_NO_FREE_STORE
;
4955 memset(ln
,0,sizeof(*ln
));
4957 ln
->ln_FileLock
.fl_Key
= (IPTR
)ln
;
4958 ln
->ln_FileLock
.fl_Access
= SHARED_LOCK
;
4959 ln
->ln_FileLock
.fl_Task
= FileSystemPort
;
4960 ln
->ln_FileLock
.fl_Volume
= MKBADDR(VolumeNode
);
4961 ln
->ln_FullName
= full_name
;
4963 SHOWSTRING(full_name
);
4965 error
= smba_open(ServerData
,full_name
,full_name_size
,&ln
->ln_File
);
4968 error
= MapErrnoToIoErr(error
);
4972 AddTail((struct List
*)&LockList
,(struct Node
*)ln
);
4973 result
= MKBADDR(&ln
->ln_FileLock
);
4974 SHOWVALUE(&ln
->ln_FileLock
);
4981 FreeMemory(full_name
);
4984 (*error_ptr
) = error
;
4990 /****************************************************************************/
4994 struct FileHandle
* fh
,
4995 struct FileLock
* fl
,
4998 LONG result
= DOSFALSE
;
4999 struct FileNode
* fn
;
5000 struct LockNode
* ln
;
5007 fn
= AllocateMemory(sizeof(*fn
));
5010 error
= ERROR_NO_FREE_STORE
;
5014 memset(fn
,0,sizeof(*fn
));
5016 ln
= (struct LockNode
*)fl
->fl_Key
;
5019 fn
->fn_FullName
= ln
->ln_FullName
;
5020 fn
->fn_File
= ln
->ln_File
;
5021 fn
->fn_Mode
= fl
->fl_Access
;
5023 Remove((struct Node
*)ln
);
5026 fh
->fh_Arg1
= (IPTR
)fn
;
5028 AddTail((struct List
*)&FileList
,(struct Node
*)fn
);
5033 (*error_ptr
) = error
;
5039 /****************************************************************************/
5046 LONG result
= DOSFALSE
;
5055 if(NOT VolumeNodeAdded
)
5057 error
= ERROR_OBJECT_IN_USE
;
5063 error
= ERROR_DISK_WRITE_PROTECTED
;
5067 /* Now for the really interesting part; the new name
5068 * is to be a NUL-terminated BCPL string, and as such
5069 * must be allocated via AllocVec().
5076 new_name
= AllocVec(1 + len
+ 1,MEMF_ANY
|MEMF_PUBLIC
);
5077 if(new_name
== NULL
)
5079 error
= ERROR_NO_FREE_STORE
;
5084 memcpy(&new_name
[1],&name
[1],len
);
5085 new_name
[len
+1] = '\0';
5089 old_name
= BADDR(VolumeNode
->dol_Name
);
5090 VolumeNode
->dol_Name
= MKBADDR(new_name
);
5096 SendDiskChange(IECLASS_DISKINSERTED
);
5102 (*error_ptr
) = error
;
5108 /****************************************************************************/
5117 LONG result
= DOSFALSE
;
5118 struct FileLock
* fl
= NULL
;
5119 struct FileNode
* fn
= NULL
;
5120 struct LockNode
* ln
= NULL
;
5127 /* Sanity check; verify parameters */
5128 if((type
!= CHANGE_LOCK
&& type
!= CHANGE_FH
) ||
5129 (new_mode
!= EXCLUSIVE_LOCK
&& new_mode
!= SHARED_LOCK
))
5131 error
= ERROR_ACTION_NOT_KNOWN
;
5135 /* Now obtain the data structures, name and mode
5136 * associated with the object in question.
5138 if(type
== CHANGE_LOCK
)
5141 ln
= (struct LockNode
*)fl
->fl_Key
;
5142 name
= ln
->ln_FullName
;
5143 old_mode
= fl
->fl_Access
;
5147 struct FileHandle
* fh
= object
;
5149 fn
= (struct FileNode
*)fh
->fh_Arg1
;
5150 name
= fn
->fn_FullName
;
5151 old_mode
= fn
->fn_Mode
;
5154 /* Do we need to change anything at all? */
5155 if(new_mode
== old_mode
)
5161 /* This is the easiest case; change an
5162 * exclusive access mode to a shared
5163 * access mode. Since the original mode
5164 * can be used by one object only,
5165 * we get away by updating the mode
5168 if(new_mode
== SHARED_LOCK
)
5170 if(type
== CHANGE_LOCK
)
5171 fl
->fl_Access
= new_mode
;
5173 fn
->fn_Mode
= new_mode
;
5179 /* Is there another shared access lock
5180 * which refers to the same object?
5182 if(FindLockNode(name
,ln
) != NULL
)
5184 error
= ERROR_OBJECT_IN_USE
;
5188 /* Is there another shared access file
5189 * which refers to the same object?
5191 if(FindFileNode(name
,fn
) != NULL
)
5193 error
= ERROR_OBJECT_IN_USE
;
5197 /* There is just one single reference
5198 * to this object; change the mode
5201 if(type
== CHANGE_LOCK
)
5202 fl
->fl_Access
= new_mode
;
5204 fn
->fn_Mode
= new_mode
;
5210 (*error_ptr
) = error
;
5216 /****************************************************************************/
5219 Action_WriteProtect(
5224 LONG result
= DOSFALSE
;
5229 if(flag
== DOSFALSE
)
5233 if(key
!= WriteProtectKey
)
5235 error
= ERROR_INVALID_LOCK
;
5239 WriteProtected
= FALSE
;
5243 SendDiskChange(IECLASS_DISKREMOVED
);
5244 SendDiskChange(IECLASS_DISKINSERTED
);
5250 if(NOT WriteProtected
)
5252 WriteProtected
= TRUE
;
5253 WriteProtectKey
= key
;
5257 SendDiskChange(IECLASS_DISKREMOVED
);
5258 SendDiskChange(IECLASS_DISKINSERTED
);
5263 error
= ERROR_INVALID_LOCK
;
5272 (*error_ptr
) = error
;
5278 /****************************************************************************/
5290 old_size
= smba_get_dircache_size(ServerData
);
5292 result
= smba_change_dircache_size(ServerData
,old_size
+ buffer_delta
);
5294 if(result
== old_size
&& buffer_delta
!= 0)
5297 (*error_ptr
) = ERROR_NO_FREE_STORE
;
5304 /****************************************************************************/
5308 struct FileLock
* parent
,
5313 LONG result
= DOSFALSE
;
5314 STRPTR full_name
= NULL
;
5315 LONG full_name_size
;
5316 smba_file_t
* file
= NULL
;
5318 UBYTE name
[MAX_FILENAME_LEN
];
5326 error
= ERROR_DISK_WRITE_PROTECTED
;
5334 struct LockNode
* ln
= (struct LockNode
*)parent
->fl_Key
;
5336 parent_name
= ln
->ln_FullName
;
5343 ConvertBString(sizeof(name
),name
,bcpl_name
);
5344 TranslateCName(name
,A2M
);
5346 error
= BuildFullName(parent_name
,name
,&full_name
,&full_name_size
);
5350 /* Trying to change the comment of the root directory? */
5351 if(full_name
== NULL
)
5353 error
= ERROR_OBJECT_IN_USE
;
5357 SHOWSTRING(full_name
);
5359 error
= smba_open(ServerData
,full_name
,full_name_size
,&file
);
5362 error
= MapErrnoToIoErr(error
);
5366 ConvertBString(sizeof(comment
),comment
,bcpl_comment
);
5368 SHOWSTRING(comment
);
5370 /* All this work and we're only doing something very silly... */
5371 if(strlen(comment
) > 0)
5373 error
= ERROR_COMMENT_TOO_BIG
;
5381 FreeMemory(full_name
);
5385 (*error_ptr
) = error
;
5391 /****************************************************************************/
5395 struct FileNode
* fn
,
5402 LONG result
= DOSFALSE
;
5406 /* Sanity checks... */
5407 if (mode
< REC_EXCLUSIVE
|| mode
> REC_SHARED_IMMED
)
5409 error
= ERROR_ACTION_NOT_KNOWN
;
5413 /* Invalid offset, size or integer overflow? */
5414 if (offset
< 0 || length
<= 0 || offset
+ length
< offset
)
5416 error
= ERROR_LOCK_COLLISION
;
5420 if ((mode
== REC_SHARED
) || (mode
== REC_SHARED_IMMED
))
5425 if ((mode
== REC_SHARED_IMMED
) || (mode
== REC_EXCLUSIVE_IMMED
))
5430 if (timeout
> 214748364)
5431 timeout
= ~0; /* wait forever */
5433 timeout
*= 20; /* milliseconds instead of Ticks */
5436 error
= smba_lockrec (fn
->fn_File
, offset
, length
, umode
, 0, (long)timeout
);
5439 error
= MapErrnoToIoErr(error
);
5447 (*error_ptr
) = error
;
5453 /****************************************************************************/
5457 struct FileNode
* fn
,
5462 LONG result
= DOSFALSE
;
5465 /* Sanity checks... */
5466 if(offset
< 0 || length
<= 0 || offset
+ length
< offset
)
5468 error
= ERROR_RECORD_NOT_LOCKED
;
5472 error
= smba_lockrec (fn
->fn_File
, offset
, length
, 2, -1, 0);
5475 error
= MapErrnoToIoErr(error
);
5483 (*error_ptr
) = error
;
5489 /****************************************************************************/
5492 StartReconnectTimer(VOID
)
5494 /* Set up delay for next try */
5495 TimerRequest
.tr_node
.io_Command
= TR_ADDREQUEST
;
5496 TimerRequest
.tr_node
.io_Message
.mn_ReplyPort
= FileSystemPort
;
5497 TimerRequest
.tr_time
.tv_secs
= 2;
5498 TimerRequest
.tr_time
.tv_micro
= 0;
5499 SendIO((struct IORequest
*)&TimerRequest
);
5503 /****************************************************************************/
5506 HandleFileSystem(VOID
)
5508 BOOL sign_off
= FALSE
;
5520 signals
= Wait(SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_F
| (1UL << FileSystemPort
->mp_SigBit
));
5522 if(signals
& (1UL << FileSystemPort
->mp_SigBit
))
5524 struct DosPacket
* dp
;
5525 struct Message
* mn
;
5528 while((mn
= GetMsg(FileSystemPort
)) != NULL
)
5530 dp
= (struct DosPacket
*)mn
->mn_Node
.ln_Name
;
5532 D(("got packet (%ld); sender '%s'\n",dp
->dp_Action
,((struct Node
*)dp
->dp_Port
->mp_SigTask
)->ln_Name
));
5537 if (mn
->mn_Node
.ln_Type
== NT_REPLYMSG
)
5539 TimerActive
= FALSE
;
5547 (args
.CacheSize
!= NULL
) ? *args
.CacheSize
: 0,
5552 if(!VolumeNodeAdded
&& dp
->dp_Action
!= ACTION_STARTUP
)
5555 res2
= ERROR_NO_DISK
;
5556 ReplyPkt(dp
,res1
,res2
);
5559 switch(dp
->dp_Action
)
5561 case ACTION_STARTUP
:
5562 /* FSSM,DeviceNode -> Bool */
5564 res1
= (IPTR
)Action_Startup(
5565 (struct FileSysStartupMsg
*)BADDR(dp
->dp_Arg2
),
5566 (struct DosList
*)BADDR(dp
->dp_Arg3
),&res2
);
5573 SHOWMSG("ACTION_DIE");
5574 if(IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
))
5576 SHOWMSG("no locks or files pending; quitting");
5582 SHOWMSG("locks or files still pending; cannot quit yet");
5585 res2
= ERROR_OBJECT_IN_USE
;
5591 case ACTION_CURRENT_VOLUME
:
5592 /* (Ignore) -> VolumeNode */
5594 res1
= (IPTR
)MKBADDR(VolumeNode
);
5597 case ACTION_LOCATE_OBJECT
:
5598 /* Lock,Name,Mode -> Lock */
5600 res1
= (IPTR
)Action_LocateObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
5603 case ACTION_RENAME_DISK
:
5606 res1
= Action_RenameDisk((UBYTE
*)BADDR(dp
->dp_Arg1
),&res2
);
5609 case ACTION_FREE_LOCK
:
5612 res1
= Action_FreeLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
5615 case ACTION_DELETE_OBJECT
:
5616 /* Lock,Name -> Bool */
5618 res1
= Action_DeleteObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
5621 case ACTION_RENAME_OBJECT
:
5622 /* Source lock,source name,destination lock,destination name -> Bool */
5624 res1
= Action_RenameObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),BADDR(dp
->dp_Arg2
),
5625 (struct FileLock
*)BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
5629 case ACTION_MORE_CACHE
:
5630 /* Buffer delta -> Total number of buffers */
5632 /* NOTE: documentation for this packet type is inconsistent;
5633 * in the 'good old' 1.x days 'res1' was documented as
5634 * the total number of buffers to be returned. In the
5635 * 2.x documentation it is said that 'res1' should
5636 * return the success code, with 'res2' to hold the
5637 * total number of buffers. However, the 'AddBuffers'
5638 * shell command doesn't work that way, and the
5639 * dos.library implementation of 'AddBuffers()' doesn't
5640 * work that way either. The 1.3 'AddBuffers' command
5641 * appears to treat a zero result as failure and a
5642 * non-zero result as success, which suggests that this
5643 * is how the packet is supposed to work, contrary to
5644 * what the official documentation says.
5646 res1
= Action_MoreCache(dp
->dp_Arg1
,&res2
);
5649 case ACTION_COPY_DIR
:
5652 res1
= (IPTR
)Action_CopyDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
5655 case ACTION_SET_PROTECT
:
5656 /* (Ignore),Lock,Name,Mask -> Bool */
5658 res1
= Action_SetProtect((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),dp
->dp_Arg4
,&res2
);
5661 case ACTION_CREATE_DIR
:
5662 /* Lock,Name -> Lock */
5664 res1
= (IPTR
)Action_CreateDir((struct FileLock
*)BADDR(dp
->dp_Arg1
),(APTR
)BADDR(dp
->dp_Arg2
),&res2
);
5667 case ACTION_EXAMINE_OBJECT
:
5668 /* FileLock,FileInfoBlock -> Bool */
5670 res1
= Action_ExamineObject((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
5673 case ACTION_EXAMINE_NEXT
:
5674 /* FileLock,FileInfoBlock -> Bool */
5676 res1
= Action_ExamineNext((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
5679 case ACTION_DISK_INFO
:
5680 /* InfoData -> Bool */
5682 Action_DiskInfo((struct InfoData
*)BADDR(dp
->dp_Arg1
),&res2
);
5688 /* FileLock,InfoData -> Bool */
5690 res1
= Action_Info((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct InfoData
*)BADDR(dp
->dp_Arg2
),&res2
);
5693 case ACTION_SET_COMMENT
:
5694 /* (Ignore),FileLock,Name,Comment -> Bool */
5696 res1
= Action_SetComment((struct FileLock
*)BADDR(dp
->dp_Arg2
),BADDR(dp
->dp_Arg3
),BADDR(dp
->dp_Arg4
),&res2
);
5702 res1
= (IPTR
)Action_Parent((struct FileLock
*)BADDR(dp
->dp_Arg1
),&res2
);
5705 case ACTION_INHIBIT
:
5707 SHOWMSG("ACTION_INHIBIT");
5711 case ACTION_SET_DATE
:
5712 /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
5714 res1
= Action_SetDate((struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),(struct DateStamp
*)dp
->dp_Arg4
,&res2
);
5717 case ACTION_SAME_LOCK
:
5718 /* Lock,Lock -> Bool */
5720 res1
= Action_SameLock((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
5724 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
5726 res1
= Action_Read((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
5730 /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
5732 res1
= Action_Write((struct FileNode
*)dp
->dp_Arg1
,(APTR
)dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
5735 case ACTION_FINDUPDATE
:
5736 case ACTION_FINDINPUT
:
5737 case ACTION_FINDOUTPUT
:
5738 /* FileHandle,FileLock,Name -> Bool */
5740 res1
= Action_Find(dp
->dp_Action
,(struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),(APTR
)BADDR(dp
->dp_Arg3
),&res2
);
5744 /* FileHandle->fh_Arg1 -> Bool */
5746 res1
= Action_End((struct FileNode
*)dp
->dp_Arg1
,&res2
);
5750 /* FileHandle->fh_Arg1,Position,Mode -> Position */
5752 res1
= Action_Seek((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
5755 case ACTION_SET_FILE_SIZE
:
5756 /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
5758 res1
= Action_SetFileSize((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
5761 case ACTION_WRITE_PROTECT
:
5762 /* Flag,Key -> Bool */
5764 res1
= Action_WriteProtect(dp
->dp_Arg1
,dp
->dp_Arg2
,&res2
);
5767 case ACTION_FH_FROM_LOCK
:
5768 /* FileHandle(BPTR),FileLock -> Bool */
5770 res1
= Action_FHFromLock((struct FileHandle
*)BADDR(dp
->dp_Arg1
),(struct FileLock
*)BADDR(dp
->dp_Arg2
),&res2
);
5773 case ACTION_IS_FILESYSTEM
:
5775 SHOWMSG("ACTION_IS_FILESYSTEM");
5779 case ACTION_CHANGE_MODE
:
5780 /* Type,Object,Mode -> Bool */
5782 res1
= Action_ChangeMode(dp
->dp_Arg1
,(APTR
)BADDR(dp
->dp_Arg2
),dp
->dp_Arg3
,&res2
);
5785 case ACTION_COPY_DIR_FH
:
5786 /* FileHandle->fh_Arg1 -> Bool */
5788 res1
= (IPTR
)Action_CopyDirFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
5791 case ACTION_PARENT_FH
:
5792 /* FileHandle->fh_Arg1 -> Bool */
5794 res1
= (IPTR
)Action_ParentFH((struct FileNode
*)dp
->dp_Arg1
,&res2
);
5797 case ACTION_EXAMINE_ALL
:
5798 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
5800 res1
= Action_ExamineAll((struct FileLock
*)BADDR(dp
->dp_Arg1
),(struct ExAllData
*)dp
->dp_Arg2
,
5801 dp
->dp_Arg3
,dp
->dp_Arg4
,(struct ExAllControl
*)dp
->dp_Arg5
,&res2
);
5805 case ACTION_EXAMINE_FH
:
5806 /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
5808 res1
= Action_ExamineFH((struct FileNode
*)dp
->dp_Arg1
,(struct FileInfoBlock
*)BADDR(dp
->dp_Arg2
),&res2
);
5811 case ACTION_EXAMINE_ALL_END
:
5812 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
5817 case ACTION_LOCK_RECORD
:
5818 /* FileHandle->fh_Arg1,position,length,mode,time-out -> Bool */
5819 res1
= Action_LockRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,dp
->dp_Arg4
,(ULONG
)dp
->dp_Arg5
,&res2
);
5822 case ACTION_FREE_RECORD
:
5823 /* FileHandle->fh_Arg1,position,length -> Bool */
5824 res1
= Action_FreeRecord((struct FileNode
*)dp
->dp_Arg1
,dp
->dp_Arg2
,dp
->dp_Arg3
,&res2
);
5829 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp
->dp_Action
,dp
->dp_Action
));
5832 res2
= ERROR_ACTION_NOT_KNOWN
;
5840 ReplyPkt(dp
,res1
,res2
);
5848 if(signals
& SIGBREAKF_CTRL_F
)
5850 struct FileNode
* fn
;
5851 struct LockNode
* ln
;
5853 D(("list of open files:"));
5855 for(fn
= (struct FileNode
*)FileList
.mlh_Head
;
5856 fn
->fn_MinNode
.mln_Succ
!= NULL
;
5857 fn
= (struct FileNode
*)fn
->fn_MinNode
.mln_Succ
)
5859 D((" name='%s'",fn
->fn_FullName
));
5860 D((" mode=%ld, offset=%ld",fn
->fn_Mode
,fn
->fn_Offset
));
5864 D(("list of allocated locks:"));
5866 for(ln
= (struct LockNode
*)LockList
.mlh_Head
;
5867 ln
->ln_MinNode
.mln_Succ
!= NULL
;
5868 ln
= (struct LockNode
*)ln
->ln_MinNode
.mln_Succ
)
5870 D((" name='%s'",ln
->ln_FullName
));
5871 D((" mode=%ld",ln
->ln_FileLock
.fl_Access
));
5878 if(signals
& SIGBREAKF_CTRL_C
)
5883 if(IsListEmpty((struct List
*)&FileList
) && IsListEmpty((struct List
*)&LockList
))
5885 SHOWMSG("no locks or files pending; quitting");
5890 SHOWMSG("locks or files still pending; cannot quit yet");
5897 LocalPrintf("stopped.\n");
5902 /****************************************************************************/
5905 * Copy src to string dst of size siz. At most siz-1 characters
5906 * will be copied. Always NUL terminates (unless siz == 0).
5907 * Returns strlen(src); if retval >= siz, truncation occurred.
5910 strlcpy(char *dst
, const char *src
, size_t siz
)
5913 const char *s
= src
;
5917 /* Copy as many bytes as will fit */
5918 if(n
!= 0 && --n
!= 0)
5922 if(((*d
++) = (*s
++)) == '\0')
5928 /* Not enough room in dst, add NUL and traverse rest of src */
5932 (*d
) = '\0'; /* NUL-terminate dst */
5934 while((*s
++) != '\0')
5938 result
= s
- src
- 1; /* count does not include NUL */
5944 * Appends src to string dst of size siz (unlike strncat, siz is the
5945 * full size of dst, not space left). At most siz-1 characters
5946 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
5947 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
5948 * If retval >= siz, truncation occurred.
5951 strlcat(char *dst
, const char *src
, size_t siz
)
5954 const char *s
= src
;
5959 /* Find the end of dst and adjust bytes left but don't go past end */
5960 while(n
-- != 0 && (*d
) != '\0')
5968 result
= dlen
+ strlen(s
);
5985 result
= dlen
+ (s
- src
); /* count does not include NUL */