Listtree.mcc: implement Listtree_Close
[AROS.git] / workbench / network / smbfs / source_code / main.c
blob99b415fd3b27aeae96baaecaebeaea77b457e494
1 /*
2 * $Id$
4 * :ts=4
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.
26 #include "smbfs.h"
28 /****************************************************************************/
30 #include "smb_abstraction.h"
32 /****************************************************************************/
34 #include <smb/smb.h>
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
54 #define tr_time Time
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;
70 #endif /* __AROS__ */
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 /****************************************************************************/
86 typedef STRPTR KEY;
87 typedef LONG * NUMBER;
88 typedef LONG SWITCH;
90 /****************************************************************************/
92 struct FileNode
94 struct MinNode fn_MinNode;
95 struct FileHandle * fn_Handle;
96 LONG fn_Offset;
97 LONG fn_Mode;
98 smba_file_t * fn_File;
99 STRPTR fn_FullName;
102 struct LockNode
104 struct MinNode ln_MinNode;
105 struct FileLock ln_FileLock;
106 smba_file_t * ln_File;
107 BOOL ln_RestartExamine;
108 UWORD ln_Pad;
109 STRPTR ln_FullName;
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. */
150 LONG _start(VOID);
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);
156 #ifndef __AROS__
157 VOID VARARGS68K ReportError(STRPTR fmt, ...);
158 #endif
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);
165 #ifndef __AROS__
166 VOID VARARGS68K SPrintf(STRPTR buffer, STRPTR formatString, ...);
167 #endif
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;
230 #endif
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__)
270 int errno;
271 #endif
272 #ifndef h_errno
273 int h_errno;
274 #endif
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;
285 STATIC BOOL Quit;
286 STATIC BOOL Quiet;
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];
313 struct
315 KEY Workgroup;
316 KEY UserName;
317 KEY Password;
318 SWITCH ChangeCase;
319 SWITCH CaseSensitive;
320 SWITCH OmitHidden;
321 SWITCH Quiet;
322 KEY ClientName;
323 KEY ServerName;
324 KEY DeviceName;
325 KEY VolumeName;
326 NUMBER CacheSize;
327 NUMBER DebugLevel;
328 NUMBER TimeZoneOffset;
329 NUMBER DSTOffset;
330 KEY TranslationFile;
331 KEY Service;
332 } args;
334 CONST TEXT control_template[] =
335 "DOMAIN=WORKGROUP/K,"
336 "USER=USERNAME/K,"
337 "PASSWORD/K,"
338 "CHANGECASE/S,"
339 "CASE=CASESENSITIVE/S,"
340 "OMITHIDDEN/S,"
341 "QUIET/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,"
349 "DST=DSTOFFSET/N/K,"
350 "TRANSLATE=TRANSLATIONFILE/K,"
351 "SERVICE/A";
353 /****************************************************************************/
355 LONG _start(VOID)
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__ */
367 #endif
369 FileSystemPort = &((*(struct Process *)FindTask(NULL)).pr_MsgPort);
371 /* Don't emit any debugging output before we are ready. */
372 SETDEBUGLEVEL(0);
374 /* Open the libraries we need and check
375 * whether we could get them.
377 DOSBase = OpenLibrary("dos.library",0);
379 #if defined(__amigaos4__)
381 if(DOSBase != NULL)
383 IDOS = (struct DOSIFace *)GetInterface(DOSBase, "main", 1, 0);
384 if(IDOS == NULL)
386 CloseLibrary(DOSBase);
387 DOSBase = NULL;
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);
400 if(IUtility == NULL)
402 CloseLibrary(UtilityBase);
403 UtilityBase = NULL;
407 #endif /* __amigaos4__ */
409 if(UtilityBase == NULL || DOSBase == NULL || DOSBase->lib_Version < MINIMUM_OS_VERSION)
410 goto out;
412 /* This needs to be set up properly for ReportError()
413 * to work.
415 NewList((struct List *)&ErrorList);
417 if(Locale != NULL)
418 SHOWVALUE(Locale->loc_GMTOffset);
420 HandleFileSystem();
422 out:
424 Cleanup();
426 return(result);
429 /****************************************************************************/
431 #ifdef __AROS__
432 #define LocalPrintf(format,args...) Printf(format ,##args )
433 #else
434 LONG VARARGS68K
435 LocalPrintf(STRPTR format, ...)
437 va_list args;
438 LONG result;
440 #if defined(__amigaos4__)
442 va_startlinear(args,format);
443 result = VPrintf(format,va_getlinearva(args,APTR));
444 va_end(args);
446 #else
448 va_start(args,format);
449 result = VPrintf(format,args);
450 va_end(args);
452 #endif /* __amigaos4__ */
454 return(result);
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.
463 STRPTR
464 amitcp_strerror(int error)
466 struct TagItem tags[2];
467 STRPTR result;
469 ENTER();
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;
479 RETURN(result);
480 return(result);
483 /****************************************************************************/
485 /* Return the descriptive text associated with a host lookup failure code. */
486 STRPTR
487 host_strerror(int error)
489 struct TagItem tags[2];
490 STRPTR result;
492 ENTER();
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;
502 RETURN(result);
503 return(result);
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
512 * to be compared.
514 LONG
515 CompareNames(STRPTR a,STRPTR b)
517 LONG result;
519 if(CaseSensitive)
520 result = strcmp(a,b);
521 else
522 result = Stricmp(a,b);
524 return(result);
527 /****************************************************************************/
529 /* Translate a string into all upper case characters. */
530 VOID
531 StringToUpper(STRPTR s)
533 UBYTE c;
535 while((c = (*s)) != '\0')
536 (*s++) = ToUpper(c);
539 /****************************************************************************/
541 /* Prepare the accumulated list of error messages for display
542 * and purge the contents of that list.
544 STATIC VOID
545 DisplayErrorList(VOID)
547 struct MinNode * last = NULL;
548 struct MinNode * mn;
549 STRPTR str = NULL;
550 STRPTR msg;
551 LONG len;
553 /* Determine how much memory will have to be
554 * allocated to hold all the accumulated
555 * error messages.
557 len = 0;
559 for(mn = ErrorList.mlh_Head ;
560 mn->mln_Succ != NULL ;
561 mn = mn->mln_Succ)
563 last = mn;
565 msg = (STRPTR)(mn + 1);
567 len += strlen(msg)+1;
570 /* Allocate the memory for the messages, then
571 * copy them there.
573 if(len > 0)
575 str = AllocVec(len,MEMF_ANY);
576 if(str != NULL)
578 str[0] = '\0';
580 for(mn = ErrorList.mlh_Head ;
581 mn->mln_Succ != NULL ;
582 mn = mn->mln_Succ)
584 msg = (STRPTR)(mn + 1);
586 strcat(str,msg);
587 if(mn != last)
588 strcat(str,"\n");
593 /* Purge the list. */
594 while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
595 FreeVec(mn);
597 /* Display the error messages. */
598 if(str != NULL)
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);
623 es.es_Title = "SMB";
624 es.es_TextFormat = str;
625 es.es_GadgetFormat = "Ok";
627 EasyRequestArgs(NULL,&es,NULL,NULL);
630 FreeVec(str);
633 #if defined(__amigaos4__)
635 if(IIntuition != NULL)
637 DropInterface((struct Interface *)IIntuition);
638 IIntuition = NULL;
641 #endif /* __amigaos4__ */
643 CloseLibrary(IntuitionBase);
644 IntuitionBase = NULL;
647 /****************************************************************************/
649 /* Release memory allocated from the global pool. */
650 VOID
651 FreeMemory(APTR address)
653 if(address != NULL)
655 ULONG * mem = address;
657 #if DEBUG
659 if(GETDEBUGLEVEL() > 0)
660 memset(address,0xA3,mem[-1] - sizeof(*mem));
662 #endif /* DEBUG */
664 FreePooled(MemoryPool,&mem[-1],mem[-1]);
668 /* Allocate memory from the global pool. */
669 APTR
670 AllocateMemory(ULONG size)
672 APTR result = NULL;
674 if(size > 0)
676 ULONG * mem;
678 size = (sizeof(*mem) + size + 7) & ~7UL;
680 mem = AllocPooled(MemoryPool,size);
681 if(mem != NULL)
683 (*mem++) = size;
685 #if DEBUG
687 if(GETDEBUGLEVEL() > 0)
688 memset(mem,0xA5,mem[-1] - sizeof(*mem));
690 #endif /* DEBUG */
692 result = mem;
696 return(result);
699 /****************************************************************************/
701 /* Obtain the number of seconds to add to the current time
702 * to translate local time into UTC.
704 LONG
705 GetTimeZoneDelta(VOID)
707 LONG seconds;
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;
722 else
724 seconds = 0;
727 return(seconds + DSTOffset);
730 /****************************************************************************/
732 /* Obtain the current time, in standard Unix format, adjusted for the
733 * local time zone.
735 ULONG
736 GetCurrentTime(VOID)
738 struct timeval tv;
739 ULONG result;
741 GetSysTime((APTR)&tv);
743 result = UNIX_TIME_OFFSET + GetTimeZoneDelta() + tv.tv_secs;
745 return(result);
748 /****************************************************************************/
750 /* Fill in a 'tm' type time specification with time information
751 * corresponding to the number of seconds provided. Input is
752 * in Unix format.
754 VOID
755 GMTime(time_t seconds,struct tm * tm)
757 struct ClockData clock_data;
759 if(seconds < UNIX_TIME_OFFSET)
760 seconds = 0;
761 else
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.
779 time_t
780 MakeTime(const struct tm * const tm)
782 struct ClockData clock_data;
783 time_t seconds;
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;
794 return(seconds);
797 /****************************************************************************/
799 /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
800 * Thanks much, Chris!
802 struct addr_entry
804 unsigned short flags;
805 unsigned char address[4];
808 struct nmb_header
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;
818 static UBYTE *
819 L1_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx)
821 int i = 0;
822 int j = 0;
823 int k;
825 while(('\0' != name[i]) && (i < 15))
827 k = ToUpper(name[i]);
828 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);
836 while(j < 30)
838 dst[j++] = i;
839 dst[j++] = k;
842 dst[30] = 'A' + ((sfx & 0xF0) >> 4);
843 dst[31] = 'A' + (sfx & 0x0F);
844 dst[32] = '\0';
846 return(dst);
849 static int
850 L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, const UBYTE * scope)
852 int lenpos;
853 int i;
854 int j;
856 if(NULL == L1_Encode(&dst[1], name, pad, sfx))
857 return(-1);
859 dst[0] = 0x20;
860 lenpos = 33;
862 if('\0' != (*scope))
866 for(i = 0, j = (lenpos + 1);
867 ('.' != scope[i]) && ('\0' != scope[i]);
868 i++, j++)
870 dst[j] = ToUpper(scope[i]);
873 dst[lenpos] = (UBYTE)i;
874 lenpos += i + 1;
875 scope += i;
877 while('.' == (*scope++));
879 dst[lenpos] = '\0';
882 return(lenpos + 1);
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] =
900 0x00, 0x20,
901 0x00, 0x01
904 struct timeval tv;
905 fd_set read_fds;
906 int sock_fd;
907 int option_true = 1;
908 struct sockaddr_in sox;
909 struct nmb_header nmb_header;
910 UBYTE buffer[512];
911 int total_len;
912 int i,n;
913 int result;
914 struct servent * s;
916 ENTER();
918 sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
919 if(sock_fd < 0)
921 SHOWMSG("couldn't get the socket");
922 result = (-errno);
923 goto out;
926 if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &option_true, sizeof(option_true)) < 0)
928 SHOWMSG("couldn't enable the broadcast option");
929 result = (-errno);
930 goto out;
933 sox.sin_family = AF_INET;
934 sox.sin_addr.s_addr = htonl(0xFFFFFFFF);
936 s = getservbyname("netbios-ns","udp");
937 if(s != NULL)
938 sox.sin_port = htons(s->s_port);
939 else
940 sox.sin_port = htons(137);
942 memcpy(buffer, header, (total_len = sizeof(header)));
944 n = L2_Encode(&buffer[total_len], name, ' ', '\0', scope);
945 if(n < 0)
947 SHOWMSG("name encoding failed");
948 result = (-EINVAL);
949 goto out;
952 total_len += n;
953 memcpy(&buffer[total_len], query_tail, sizeof(query_tail));
954 total_len += sizeof(query_tail);
956 result = (-ENOENT);
957 n = 0;
959 /* Send the query packet; retry five times with a one second
960 * delay in between.
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");
967 result = (-errno);
968 goto out;
971 /* Wait for a response to arrive. */
972 tv.tv_secs = 1;
973 tv.tv_micro = 0;
975 FD_ZERO(&read_fds);
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);
981 if(n < 0)
983 SHOWMSG("could not pick up the response packet");
984 result = (-errno);
985 goto out;
987 else if (n > 0)
989 break;
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
1002 * the name.
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)
1008 int start;
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);
1014 if(start < n)
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);
1034 result = 0;
1038 break;
1044 out:
1046 if(sock_fd >= 0)
1047 CloseSocket(sock_fd);
1049 RETURN(result);
1050 return(result);
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.
1057 * Workbench.
1059 STATIC VOID
1060 SendDiskChange(ULONG class)
1062 struct IOStdReq * input_request = NULL;
1063 struct MsgPort * input_port;
1064 struct InputEvent ie;
1066 ENTER();
1068 input_port = CreateMsgPort();
1069 if(input_port == NULL)
1070 goto out;
1072 input_request = (struct IOStdReq *)CreateIORequest(input_port,sizeof(*input_request));
1073 if(input_request == NULL)
1074 goto out;
1076 if(OpenDevice("input.device",0,(struct IORequest *)input_request,0) != OK)
1077 goto out;
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);
1092 out:
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);
1104 LEAVE();
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)
1124 result = fn;
1125 break;
1129 return(result);
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)
1147 result = ln;
1148 break;
1152 return(result);
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
1160 * trying to avoid.
1162 STATIC LONG
1163 CheckAccessModeCollision(STRPTR name,LONG mode)
1165 struct LockNode * ln;
1166 struct FileNode * fn;
1167 LONG error = OK;
1169 ENTER();
1170 SHOWSTRING(name);
1172 fn = FindFileNode(name,NULL);
1173 if(fn != 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;
1179 goto out;
1183 ln = FindLockNode(name,NULL);
1184 if(ln != 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;
1190 goto out;
1194 out:
1196 RETURN(error);
1197 return(error);
1200 /* Find out whether there already exists a reference to a
1201 * certain file or directory.
1203 STATIC LONG
1204 NameAlreadyInUse(STRPTR name)
1206 LONG error = OK;
1208 ENTER();
1210 if(FindFileNode(name,NULL) != NULL)
1212 error = ERROR_OBJECT_IN_USE;
1213 goto out;
1216 if(FindLockNode(name,NULL) != NULL)
1218 error = ERROR_OBJECT_IN_USE;
1219 goto out;
1222 out:
1224 RETURN(error);
1225 return(error);
1228 /* Check whether an Amiga file name uses special characters which
1229 * should be avoided when used with the SMB file sharing protocol.
1231 STATIC BOOL
1232 IsReservedName(STRPTR name)
1234 BOOL result = FALSE;
1236 /* Disallow "." and "..". */
1237 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
1239 result = TRUE;
1241 else
1243 UBYTE c;
1245 /* Disallow the use of the backslash in file names. */
1246 while((c = (*name++)) != '\0')
1248 if(c == SMB_PATH_SEPARATOR)
1250 result = TRUE;
1251 break;
1256 return(result);
1259 /****************************************************************************/
1261 /* Convert a POSIX error code into an AmigaDOS error code. */
1262 STATIC LONG
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 */
1280 #ifdef ENOTBLK
1281 { ENOTBLK, ERROR_OBJECT_WRONG_TYPE }, /* Block device required */
1282 #endif
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 */
1322 #ifdef EUSERS
1323 { EUSERS, ERROR_TASK_TABLE_FULL }, /* Too many users */
1324 #endif
1325 { EDQUOT, ERROR_DISK_FULL }, /* Disc quota exceeded */
1326 { ENOLCK, ERROR_NOT_IMPLEMENTED }, /* no locks available */
1327 { -1, -1 }
1330 LONG result = ERROR_ACTION_NOT_KNOWN;
1331 LONG i;
1333 ENTER();
1335 if(error < 0)
1336 error = (-error);
1338 for(i = 0 ; Map[i][0] != -1 ; i++)
1340 if(Map[i][0] == error)
1342 result = Map[i][1];
1343 break;
1347 RETURN(result);
1348 return(result);
1351 /****************************************************************************/
1353 /* Translate a BCPL style file name (i.e. length is in the first byte)
1354 * via a mapping table.
1356 INLINE STATIC VOID
1357 TranslateBName(UBYTE * name,UBYTE * map)
1359 if(TranslateNames)
1361 LONG len;
1362 UBYTE c;
1364 #if !defined(N__AROS__)
1365 len = (*name++);
1366 #else
1367 len = AROS_BSTR_strlen(name);
1368 name = AROS_BSTR_ADDR(name);
1369 #endif
1370 while(len-- > 0)
1372 c = (*name);
1374 (*name++) = map[c];
1379 /* Translate a NUL terminated file name via a mapping table. */
1380 INLINE STATIC VOID
1381 TranslateCName(UBYTE * name,UBYTE * map)
1383 if(TranslateNames)
1385 UBYTE c;
1387 while((c = (*name)) != '\0')
1388 (*name++) = map[c];
1392 /****************************************************************************/
1394 /* Remove a DosList entry using the proper protocols. Note that
1395 * this function can fail!
1397 STATIC BOOL
1398 ReallyRemoveDosEntry(struct DosList * entry)
1400 struct Message * mn;
1401 struct MsgPort * port;
1402 struct DosList * dl;
1403 BOOL result = FALSE;
1404 LONG kind,i;
1406 if(entry->dol_Type == DLT_DEVICE)
1407 kind = LDF_DEVICES;
1408 else
1409 kind = LDF_VOLUMES;
1411 port = entry->dol_Task;
1413 for(i = 0 ; i < 100 ; i++)
1415 dl = AttemptLockDosList(LDF_WRITE|kind);
1416 if(((IPTR)dl) <= 1)
1417 dl = NULL;
1419 if(dl != NULL)
1421 RemDosEntry(entry);
1423 UnLockDosList(LDF_WRITE|kind);
1425 result = TRUE;
1427 break;
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);
1436 return(result);
1439 /****************************************************************************/
1441 /* Release all resources allocated by the Setup() routine. */
1442 STATIC VOID
1443 Cleanup(VOID)
1445 BOOL send_disk_change = FALSE;
1447 ENTER();
1449 /* If any errors have cropped up, display them now before
1450 * call it quits.
1452 DisplayErrorList();
1454 if(Parameters != NULL)
1456 FreeArgs(Parameters);
1457 FreeDosObject(DOS_RDARGS, Parameters);
1458 Parameters = NULL;
1461 if(Icon != NULL)
1463 FreeDiskObject(Icon);
1464 Icon = NULL;
1467 if(ServerData != NULL)
1469 smba_disconnect(ServerData);
1470 ServerData = NULL;
1473 if(DeviceNode != NULL)
1475 if(ReallyRemoveDosEntry(DeviceNode))
1476 FreeDosEntry(DeviceNode);
1477 DeviceNode = NULL;
1480 if(VolumeNode != NULL)
1482 if(VolumeNodeAdded)
1484 if(ReallyRemoveDosEntry(VolumeNode))
1485 FreeDosEntry(VolumeNode);
1487 send_disk_change = TRUE;
1489 else
1491 FreeDosEntry(VolumeNode);
1494 VolumeNode = NULL;
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__)
1511 if(ITimer != NULL)
1513 DropInterface((struct Interface *)ITimer);
1514 ITimer = NULL;
1517 #endif /* __amigaos4__ */
1519 if(TimerBase != NULL)
1521 if(TimerActive)
1523 AbortIO((struct IORequest *)&TimerRequest);
1524 WaitIO((struct IORequest *)&TimerRequest);
1526 CloseDevice((struct IORequest *)&TimerRequest);
1527 TimerBase = NULL;
1530 #if defined(__amigaos4__)
1532 if(ISocket != NULL)
1534 DropInterface((struct Interface *)ISocket);
1535 ISocket = NULL;
1538 #endif /* __amigaos4__ */
1540 if(SocketBase != NULL)
1542 CloseLibrary(SocketBase);
1543 SocketBase = NULL;
1546 #if defined(__amigaos4__)
1548 if(IUtility != NULL)
1550 DropInterface((struct Interface *)IUtility);
1551 IUtility = NULL;
1554 #endif /* __amigaos4__ */
1556 if(UtilityBase != NULL)
1558 CloseLibrary(UtilityBase);
1559 UtilityBase = NULL;
1562 #if defined(__amigaos4__)
1564 if(IIcon != NULL)
1566 DropInterface((struct Interface *)IIcon);
1567 IIcon = NULL;
1570 #endif /* __amigaos4__ */
1572 if(IconBase != NULL)
1574 CloseLibrary(IconBase);
1575 IconBase = NULL;
1578 if(Locale != NULL)
1580 CloseLocale(Locale);
1581 Locale = NULL;
1584 #if defined(__amigaos4__)
1586 if(ILocale != NULL)
1588 DropInterface((struct Interface *)ILocale);
1589 ILocale = NULL;
1592 #endif /* __amigaos4__ */
1594 if(LocaleBase != NULL)
1596 CloseLibrary(LocaleBase);
1597 LocaleBase = NULL;
1600 if(MemoryPool != NULL)
1602 DeletePool(MemoryPool);
1603 MemoryPool = NULL;
1606 #if defined(__amigaos4__)
1608 if(IDOS != NULL)
1610 DropInterface((struct Interface *)IDOS);
1611 IDOS = NULL;
1614 #endif /* __amigaos4__ */
1616 if(DOSBase != NULL)
1618 CloseLibrary(DOSBase);
1619 DOSBase = NULL;
1622 if(WBStartup != NULL)
1624 Forbid();
1625 ReplyMsg((struct Message *)WBStartup);
1628 LEAVE();
1631 /****************************************************************************/
1633 /* Allocate all the necessary resources to get going. */
1634 STATIC BOOL
1635 Setup(
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;
1643 int error = OK;
1644 LONG i;
1646 ENTER();
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.");
1655 goto out;
1658 LocaleBase = OpenLibrary("locale.library",38);
1660 #if defined(__amigaos4__)
1662 if(LocaleBase != NULL)
1664 ILocale = (struct LocaleIFace *)GetInterface(LocaleBase, "main", 1, 0);
1665 if(ILocale == NULL)
1667 CloseLibrary(LocaleBase);
1668 LocaleBase = NULL;
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'.");
1692 goto out;
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);
1702 if(ITimer == NULL)
1704 ReportError("Could not open 'timer.device'.");
1705 goto out;
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);
1718 if(ISocket == NULL)
1720 CloseLibrary(SocketBase);
1721 SocketBase = NULL;
1725 #endif /* __amigaos4__ */
1727 if(SocketBase == NULL)
1729 ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
1730 goto out;
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,
1738 TAG_END);
1739 if(error != OK)
1741 ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
1742 goto out;
1745 if(opt_changecase)
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)
1756 STRPTR msg = NULL;
1757 BPTR file;
1759 error = OK;
1761 file = Open(translation_file,MODE_OLDFILE);
1762 if(file != ZERO)
1764 if(Read(file,A2M,256) != 256 ||
1765 Read(file,M2A,256) != 256)
1767 msg = "Could not read translation file";
1768 error = IoErr();
1771 Close(file);
1773 else
1775 msg = "Could not open translation file";
1776 error = IoErr();
1779 if(msg == NULL)
1781 TranslateNames = TRUE;
1783 else
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);
1795 goto out;
1799 result = TRUE;
1801 out:
1803 RETURN(result);
1804 return(result);
1807 /****************************************************************************/
1810 /* Make connection to server and make a volume for it. */
1811 STATIC BOOL
1812 AddVolume(
1813 STRPTR service,
1814 STRPTR workgroup,
1815 STRPTR username,
1816 STRPTR opt_password,
1817 STRPTR opt_clientname,
1818 STRPTR opt_servername,
1819 int opt_cachesize,
1820 STRPTR device_name,
1821 STRPTR volume_name)
1823 BOOL result = FALSE;
1824 int error = OK;
1825 STRPTR actual_volume_name;
1826 LONG actual_volume_name_len;
1827 UBYTE name[MAX_FILENAME_LEN];
1828 LONG i;
1830 ENTER();
1832 error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,&ServerData);
1833 if(error < 0)
1835 StartReconnectTimer();
1836 goto out;
1839 /* Examine the volume name; make sure that it is
1840 * well-formed.
1842 if(volume_name == NULL)
1843 actual_volume_name = device_name;
1844 else
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);
1856 goto out;
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);
1870 goto out;
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.");
1881 goto out;
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. */
1899 if(VolumeNodeAdded)
1900 SendDiskChange(IECLASS_DISKINSERTED);
1902 result = TRUE;
1904 out:
1906 RETURN(result);
1907 return(result);
1910 /****************************************************************************/
1913 /* Convert a BCPL string into a standard NUL terminated 'C' string. */
1914 INLINE STATIC VOID
1915 ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
1917 #ifdef AROS_FAST_BSTR
1918 strncpy(cstring, bstring, max_len);
1919 #else
1920 STRPTR from = bstring;
1921 LONG len = from[0];
1923 if(len > max_len-1)
1924 len = max_len-1;
1926 if(len > 0)
1927 memcpy(cstring,from+1,len);
1929 cstring[len] = '\0';
1930 #endif
1933 /* Convert a NUL terminated 'C' string into a BCPL string. */
1934 INLINE STATIC VOID
1935 ConvertCString(LONG max_len, APTR bstring, STRPTR cstring)
1937 LONG len = strlen(cstring);
1938 STRPTR to = bstring;
1940 if(len > max_len-1)
1941 len = max_len-1;
1943 (*to++) = len;
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.
1954 STATIC LONG
1955 BuildFullName(
1956 STRPTR parent_name,
1957 STRPTR name,
1958 STRPTR * result_ptr,
1959 LONG * result_size_ptr)
1961 LONG error = OK;
1962 STRPTR buffer;
1963 LONG len,size;
1964 LONG i;
1966 ENTER();
1968 SHOWSTRING(parent_name);
1969 SHOWSTRING(name);
1971 (*result_ptr) = NULL;
1973 /* Throw everything left of the colon away. */
1974 if(name != NULL)
1976 for(i = 0 ; i < (LONG)strlen(name) ; i++)
1978 if(name[i] == ':')
1980 name = &name[i+1];
1981 break;
1986 /* Now, how much room is needed for the complete
1987 * path to fit into a buffer?
1989 len = 2;
1991 if(parent_name != NULL)
1992 len += strlen(parent_name) + 1;
1994 if(name != NULL)
1995 len += strlen(name) + 1;
1997 if(len < SMB_MAXNAMELEN)
1998 len = SMB_MAXNAMELEN;
2000 size = len + 3;
2002 buffer = AllocateMemory(size);
2003 if(buffer == NULL)
2005 error = ERROR_NO_FREE_STORE;
2006 goto out;
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)
2014 parent_name++;
2016 buffer[0] = SMB_PATH_SEPARATOR;
2017 strcpy(&buffer[1],parent_name);
2019 else
2021 strcpy(buffer,SMB_ROOT_DIR_NAME);
2024 /* If there's a name to add, do just that. */
2025 if(name != NULL)
2027 LONG segment_start;
2028 LONG segment_len;
2029 LONG buffer_len;
2030 LONG name_len;
2032 buffer_len = strlen(buffer);
2033 name_len = strlen(name);
2035 segment_start = 0;
2037 while(TRUE)
2039 segment_len = 0;
2041 /* Extract the next path name segment. */
2042 for(i = segment_start ; i <= name_len ; i++)
2044 if(i == name_len)
2046 segment_len = i - segment_start;
2047 break;
2049 else if (name[i] == '/')
2051 segment_len = i - segment_start + 1;
2052 break;
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';
2062 break;
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? */
2071 if(buffer_len <= 1)
2073 FreeMemory(buffer);
2074 buffer = NULL;
2076 goto out;
2078 else
2080 /* Skip the last path component. */
2081 for(i = 1 ; i <= buffer_len ; i++)
2083 if(i == buffer_len)
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.
2091 buffer_len = 1;
2092 break;
2094 else if (buffer[buffer_len-i] == SMB_PATH_SEPARATOR)
2096 /* This removes both the path separator and
2097 * the name following it.
2099 buffer_len -= i;
2100 break;
2105 else
2107 /* Add a proper separator character if
2108 * necessary.
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;
2118 else
2119 len = segment_len;
2121 memcpy(&buffer[buffer_len],&name[segment_start],len);
2122 buffer_len += len;
2125 segment_start += segment_len;
2129 (*result_ptr) = buffer;
2130 (*result_size_ptr) = size;
2132 SHOWSTRING(buffer);
2134 out:
2136 if(error != OK)
2137 FreeMemory(buffer);
2139 RETURN(error);
2140 return(error);
2143 /****************************************************************************/
2145 STATIC BOOL
2146 Action_Startup(
2147 struct FileSysStartupMsg * fssm,
2148 struct DosList * device_node,
2149 SIPTR * error_ptr)
2151 UBYTE *control;
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;
2159 LONG error = 0;
2161 ENTER();
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)
2170 goto out;
2171 control = (UBYTE *)
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)
2178 goto out;
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;
2188 else
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;
2216 else
2218 ReportError("Required 'SERVICE' parameter was not provided.");
2219 goto out;
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);
2244 else
2245 SETDEBUGLEVEL(0);
2247 D(("%s (%s)",VERS,DATE));
2249 if(Setup(
2250 args.Password,
2251 args.ChangeCase,
2252 args.TimeZoneOffset,
2253 args.DSTOffset,
2254 args.TranslationFile))
2256 AddVolume(
2257 args.Service,
2258 args.Workgroup,
2259 args.UserName,
2260 args.Password,
2261 args.ClientName,
2262 args.ServerName,
2263 cache_size,
2264 args.DeviceName,
2265 args.VolumeName);
2267 else
2269 result = FALSE;
2272 out:
2274 (*error_ptr) = error;
2276 RETURN(result);
2277 return(result);
2280 /****************************************************************************/
2282 STATIC BPTR
2283 Action_Parent(
2284 struct FileLock * parent,
2285 SIPTR * error_ptr)
2287 BPTR result = ZERO;
2288 STRPTR full_name = NULL;
2289 LONG full_name_size;
2290 STRPTR parent_name;
2291 BOOL cleanup = TRUE;
2292 struct LockNode * ln = NULL;
2293 LONG error;
2295 ENTER();
2297 SHOWVALUE(parent);
2299 if(parent != NULL)
2301 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2303 parent_name = parent_ln->ln_FullName;
2305 else
2307 parent_name = NULL;
2310 error = BuildFullName(parent_name,"/",&full_name,&full_name_size);
2311 if(error != OK)
2312 goto out;
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)
2319 goto out;
2321 ln = AllocateMemory(sizeof(*ln));
2322 if(ln == NULL)
2324 error = ERROR_NO_FREE_STORE;
2325 goto out;
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);
2339 if(error < 0)
2341 error = MapErrnoToIoErr(error);
2342 goto out;
2345 AddTail((struct List *)&LockList,(struct Node *)ln);
2346 result = MKBADDR(&ln->ln_FileLock);
2347 cleanup = FALSE;
2348 SHOWVALUE(&ln->ln_FileLock);
2350 out:
2352 if(cleanup)
2354 FreeMemory(full_name);
2355 FreeMemory(ln);
2358 (*error_ptr) = error;
2360 RETURN(result);
2361 return(result);
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;
2376 if(last_ln != NULL)
2377 start = (struct LockNode *)last_ln->ln_MinNode.mln_Succ;
2378 else
2379 start = (struct LockNode *)LockList.mlh_Head;
2381 for(ln = start ;
2382 ln->ln_MinNode.mln_Succ != NULL ;
2383 ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
2385 if(CompareNames(name,ln->ln_FullName) == SAME)
2387 result = ln;
2388 break;
2392 return(result);
2395 /****************************************************************************/
2397 STATIC LONG
2398 Action_DeleteObject(
2399 struct FileLock * parent,
2400 APTR bcpl_name,
2401 SIPTR * error_ptr)
2403 LONG result = DOSFALSE;
2404 STRPTR full_name = NULL;
2405 LONG full_name_size;
2406 smba_file_t * file = NULL;
2407 STRPTR parent_name;
2408 STRPTR full_parent_name = NULL;
2409 UBYTE name[MAX_FILENAME_LEN];
2410 struct LockNode * ln;
2411 smba_stat_t st;
2412 LONG error;
2414 ENTER();
2416 if(WriteProtected)
2418 error = ERROR_DISK_WRITE_PROTECTED;
2419 goto out;
2422 SHOWVALUE(parent);
2424 if(parent != NULL)
2426 ln = (struct LockNode *)parent->fl_Key;
2428 parent_name = ln->ln_FullName;
2430 else
2432 parent_name = NULL;
2435 ConvertBString(sizeof(name),name,bcpl_name);
2436 TranslateCName(name,A2M);
2438 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2439 if(error != OK)
2440 goto out;
2442 /* Trying to delete the root directory, are you kidding? */
2443 if(full_name == NULL)
2445 error = ERROR_OBJECT_WRONG_TYPE;
2446 goto out;
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;
2457 goto out;
2460 strcpy(full_parent_name,full_name);
2462 /* Build the parent object name - Piru */
2463 if (full_parent_name[0] != '\0')
2465 int i;
2467 i = strlen(full_parent_name) - 1;
2468 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2469 i--;
2471 for ( ; i >= 0 ; i--)
2473 if (full_parent_name[i] == SMB_PATH_SEPARATOR)
2475 full_parent_name[i] = '\0';
2476 break;
2481 /* NOTE: Mark all locks to this object as restart, not just first
2482 one - Piru */
2483 ln = NULL;
2484 while ((ln = FindNextLockNode(full_parent_name, ln)) != NULL)
2485 ln->ln_RestartExamine = TRUE;
2487 ln = FindLockNode(full_parent_name,NULL);
2488 if(ln != 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);
2497 if(error < 0)
2499 error = MapErrnoToIoErr(error);
2500 goto out;
2503 error = smba_getattr(file,&st);
2504 if(error < 0)
2506 error = MapErrnoToIoErr(error);
2507 goto out;
2510 smba_close(file);
2511 file = NULL;
2513 if(st.is_dir)
2515 SHOWMSG("removing a directory");
2517 error = smba_rmdir(ServerData,full_name);
2518 if(error < 0)
2520 SHOWVALUE(error);
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;
2529 else
2530 error = MapErrnoToIoErr(error);
2532 goto out;
2535 else
2537 SHOWMSG("removing a file");
2539 error = smba_remove(ServerData,full_name);
2540 if(error < 0)
2542 SHOWVALUE(error);
2544 error = MapErrnoToIoErr(error);
2545 goto out;
2549 SHOWMSG("done.");
2551 result = DOSTRUE;
2553 out:
2555 FreeMemory(full_name);
2556 FreeMemory(full_parent_name);
2557 if(file != NULL)
2558 smba_close(file);
2560 (*error_ptr) = error;
2562 RETURN(result);
2563 return(result);
2566 /****************************************************************************/
2568 STATIC BPTR
2569 Action_CreateDir(
2570 struct FileLock * parent,
2571 APTR bcpl_name,
2572 SIPTR * error_ptr)
2574 BPTR result = ZERO;
2575 STRPTR full_name = NULL;
2576 LONG full_name_size;
2577 struct LockNode * ln = NULL;
2578 STRPTR parent_name;
2579 STRPTR dir_name = NULL;
2580 smba_file_t * dir = NULL;
2581 STRPTR base_name;
2582 UBYTE name[MAX_FILENAME_LEN];
2583 LONG error;
2584 LONG i;
2586 ENTER();
2588 if(WriteProtected)
2590 error = ERROR_DISK_WRITE_PROTECTED;
2591 goto out;
2594 SHOWVALUE(parent);
2596 if(parent != NULL)
2598 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2600 parent_name = parent_ln->ln_FullName;
2602 else
2604 parent_name = NULL;
2607 ConvertBString(sizeof(name),name,bcpl_name);
2608 TranslateCName(name,A2M);
2610 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2611 if(error != OK)
2612 goto out;
2614 /* Trying to overwrite the root directory, are you kidding? */
2615 if(full_name == NULL)
2617 error = ERROR_OBJECT_IN_USE;
2618 goto out;
2621 dir_name = AllocateMemory(strlen(full_name)+3);
2622 if(dir_name == NULL)
2624 error = ERROR_NO_FREE_STORE;
2625 goto out;
2628 strcpy(dir_name,full_name);
2629 base_name = NULL;
2630 for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
2632 if(dir_name[i] == SMB_PATH_SEPARATOR)
2634 if(i == 0)
2636 memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1);
2637 i++;
2640 dir_name[i] = '\0';
2642 base_name = &dir_name[i+1];
2643 break;
2647 ln = AllocateMemory(sizeof(*ln));
2648 if(ln == NULL)
2650 error = ERROR_NO_FREE_STORE;
2651 goto out;
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);
2663 if(error < 0)
2665 error = MapErrnoToIoErr(error);
2666 goto out;
2669 error = smba_mkdir(dir,base_name);
2670 if(error < 0)
2672 error = MapErrnoToIoErr(error);
2673 goto out;
2676 smba_close(dir);
2677 dir = NULL;
2679 SHOWSTRING(full_name);
2681 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2682 if(error < 0)
2684 error = MapErrnoToIoErr(error);
2685 goto out;
2688 AddTail((struct List *)&LockList,(struct Node *)ln);
2689 result = MKBADDR(&ln->ln_FileLock);
2690 SHOWVALUE(&ln->ln_FileLock);
2692 out:
2694 if(dir != NULL)
2695 smba_close(dir);
2697 FreeMemory(dir_name);
2699 if(result == ZERO)
2701 FreeMemory(full_name);
2702 FreeMemory(ln);
2705 (*error_ptr) = error;
2707 RETURN(result);
2708 return(result);
2711 /****************************************************************************/
2713 STATIC BPTR
2714 Action_LocateObject(
2715 struct FileLock * parent,
2716 APTR bcpl_name,
2717 LONG mode,
2718 SIPTR * error_ptr)
2720 BPTR result = ZERO;
2721 STRPTR full_name = NULL;
2722 LONG full_name_size;
2723 struct LockNode * ln = NULL;
2724 STRPTR parent_name;
2725 UBYTE name[MAX_FILENAME_LEN];
2726 LONG error;
2728 ENTER();
2730 SHOWVALUE(parent);
2732 if(parent != NULL)
2734 struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key;
2736 parent_name = parent_ln->ln_FullName;
2738 else
2740 parent_name = NULL;
2743 ConvertBString(sizeof(name),name,bcpl_name);
2744 TranslateCName(name,A2M);
2746 if(IsReservedName(FilePart(name)))
2748 error = ERROR_OBJECT_NOT_FOUND;
2749 goto out;
2752 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
2753 if(error != OK)
2754 goto out;
2756 /* Trying to get a lock on the root directory's parent?
2757 * My pleasure.
2759 if(full_name == NULL)
2761 error = ERROR_OBJECT_NOT_FOUND;
2762 goto out;
2765 ln = AllocateMemory(sizeof(*ln));
2766 if(ln == NULL)
2768 error = ERROR_NO_FREE_STORE;
2769 goto out;
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);
2781 if(error != OK)
2782 goto out;
2784 SHOWSTRING(full_name);
2786 error = smba_open(ServerData,full_name,full_name_size,&ln->ln_File);
2787 if(error < 0)
2789 error = MapErrnoToIoErr(error);
2790 goto out;
2793 AddTail((struct List *)&LockList,(struct Node *)ln);
2794 result = MKBADDR(&ln->ln_FileLock);
2795 SHOWVALUE(&ln->ln_FileLock);
2797 out:
2799 if(result == ZERO)
2801 FreeMemory(full_name);
2802 FreeMemory(ln);
2805 (*error_ptr) = error;
2807 RETURN(result);
2808 return(result);
2811 /****************************************************************************/
2813 STATIC BPTR
2814 Action_CopyDir(
2815 struct FileLock * lock,
2816 SIPTR * error_ptr)
2818 BPTR result = ZERO;
2819 STRPTR full_name = NULL;
2820 LONG full_name_size;
2821 struct LockNode * ln = NULL;
2822 STRPTR source_name;
2823 LONG source_mode;
2824 LONG error;
2826 ENTER();
2828 SHOWVALUE(lock);
2830 if(lock != NULL && lock->fl_Access != SHARED_LOCK)
2832 SHOWMSG("cannot duplicate exclusive lock");
2833 error = ERROR_OBJECT_IN_USE;
2834 goto out;
2837 ln = AllocateMemory(sizeof(*ln));
2838 if(ln == NULL)
2840 error = ERROR_NO_FREE_STORE;
2841 goto out;
2844 memset(ln,0,sizeof(*ln));
2846 if(lock != NULL)
2848 struct LockNode * source = (struct LockNode *)lock->fl_Key;
2850 source_name = source->ln_FullName;
2851 source_mode = source->ln_FileLock.fl_Access;
2853 else
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;
2867 goto out;
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);
2881 if(error < 0)
2883 error = MapErrnoToIoErr(error);
2884 goto out;
2887 AddTail((struct List *)&LockList,(struct Node *)ln);
2888 result = MKBADDR(&ln->ln_FileLock);
2889 SHOWVALUE(&ln->ln_FileLock);
2891 out:
2893 if(result == ZERO)
2895 FreeMemory(full_name);
2896 FreeMemory(ln);
2899 (*error_ptr) = error;
2901 RETURN(result);
2902 return(result);
2905 /****************************************************************************/
2907 STATIC LONG
2908 Action_FreeLock(
2909 struct FileLock * lock,
2910 SIPTR * error_ptr)
2912 LONG result = DOSTRUE;
2913 struct LockNode * ln;
2914 LONG error = OK;
2916 ENTER();
2918 SHOWVALUE(lock);
2920 if(lock == NULL)
2921 goto out;
2923 ln = (struct LockNode *)lock->fl_Key;
2925 Remove((struct Node *)ln);
2926 smba_close(ln->ln_File);
2927 FreeMemory(ln->ln_FullName);
2928 FreeMemory(ln);
2930 out:
2932 (*error_ptr) = error;
2934 RETURN(result);
2935 return(result);
2938 /****************************************************************************/
2940 STATIC LONG
2941 Action_SameLock(
2942 struct FileLock * lock1,
2943 struct FileLock * lock2,
2944 SIPTR * error_ptr)
2946 LONG result = DOSFALSE;
2947 STRPTR name1;
2948 STRPTR name2;
2949 LONG error = OK;
2951 ENTER();
2953 SHOWVALUE(lock1);
2954 SHOWVALUE(lock2);
2956 if(lock1 != NULL)
2958 struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
2960 name1 = ln->ln_FullName;
2962 else
2964 name1 = SMB_ROOT_DIR_NAME;
2967 if(lock2 != NULL)
2969 struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
2971 name2 = ln->ln_FullName;
2973 else
2975 name2 = SMB_ROOT_DIR_NAME;
2978 SHOWSTRING(name1);
2979 SHOWSTRING(name2);
2981 if(Stricmp(name1,name2) == SAME)
2982 result = DOSTRUE;
2984 (*error_ptr) = error;
2986 RETURN(result);
2987 return(result);
2990 /****************************************************************************/
2992 STATIC LONG
2993 Action_SetProtect(
2994 struct FileLock * parent,
2995 APTR bcpl_name,
2996 LONG mask,
2997 SIPTR * error_ptr)
2999 LONG result = DOSFALSE;
3000 STRPTR full_name = NULL;
3001 LONG full_name_size;
3002 smba_file_t * file = NULL;
3003 STRPTR parent_name;
3004 UBYTE name[MAX_FILENAME_LEN];
3005 smba_stat_t st;
3006 LONG error;
3008 ENTER();
3010 if(WriteProtected)
3012 error = ERROR_DISK_WRITE_PROTECTED;
3013 goto out;
3016 SHOWVALUE(parent);
3018 if(parent != NULL)
3020 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
3022 parent_name = ln->ln_FullName;
3024 else
3026 parent_name = NULL;
3029 ConvertBString(sizeof(name),name,bcpl_name);
3030 TranslateCName(name,A2M);
3032 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
3033 if(error != OK)
3034 goto out;
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;
3042 goto out;
3045 SHOWSTRING(full_name);
3047 error = smba_open(ServerData,full_name,full_name_size,&file);
3048 if(error < 0)
3050 error = MapErrnoToIoErr(error);
3051 goto out;
3054 memset(&st,0,sizeof(st));
3056 mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
3058 st.atime = -1;
3059 st.ctime = -1;
3060 st.mtime = -1;
3061 st.size = -1;
3063 if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
3065 SHOWMSG("write protection enabled");
3066 st.is_wp = TRUE;
3068 else
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);
3082 if(error < 0)
3084 error = MapErrnoToIoErr(error);
3085 goto out;
3088 result = DOSTRUE;
3090 out:
3092 FreeMemory(full_name);
3093 if(file != NULL)
3094 smba_close(file);
3096 (*error_ptr) = error;
3098 RETURN(result);
3099 return(result);
3102 /****************************************************************************/
3104 STATIC LONG
3105 Action_RenameObject(
3106 struct FileLock * source_lock,
3107 APTR source_bcpl_name,
3108 struct FileLock * destination_lock,
3109 APTR destination_bcpl_name,
3110 SIPTR * error_ptr)
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];
3119 STRPTR parent_name;
3120 LONG error;
3122 ENTER();
3124 if(WriteProtected)
3126 error = ERROR_DISK_WRITE_PROTECTED;
3127 goto out;
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;
3139 else
3141 parent_name = NULL;
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);
3148 if(error != OK)
3149 goto out;
3151 /* Trying to rename the root directory, are you kidding? */
3152 if(full_source_name == NULL)
3154 error = ERROR_OBJECT_IN_USE;
3155 goto out;
3158 if(destination_lock != NULL)
3160 ln = (struct LockNode *)destination_lock->fl_Key;
3162 parent_name = ln->ln_FullName;
3164 else
3166 parent_name = NULL;
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);
3173 if(error != OK)
3174 goto out;
3176 /* Trying to rename the root directory, are you kidding? */
3177 if(full_destination_name == NULL)
3179 error = ERROR_OBJECT_IN_USE;
3180 goto out;
3183 error = NameAlreadyInUse(full_source_name);
3184 if(error != OK)
3185 goto out;
3187 error = NameAlreadyInUse(full_destination_name);
3188 if(error != OK)
3189 goto out;
3191 SHOWSTRING(full_source_name);
3192 SHOWSTRING(full_destination_name);
3194 error = smba_rename(ServerData,full_source_name,full_destination_name);
3195 if(error < 0)
3197 error = MapErrnoToIoErr(error);
3198 goto out;
3201 result = DOSTRUE;
3203 out:
3205 FreeMemory(full_source_name);
3206 FreeMemory(full_destination_name);
3208 (*error_ptr) = error;
3210 RETURN(result);
3211 return(result);
3214 /****************************************************************************/
3216 STATIC LONG
3217 Action_DiskInfo(
3218 struct InfoData * id,
3219 SIPTR * error_ptr)
3221 LONG result = DOSTRUE;
3222 long block_size;
3223 long num_blocks;
3224 long num_blocks_free;
3225 LONG error;
3227 ENTER();
3229 memset(id,0,sizeof(*id));
3231 if(WriteProtected)
3232 id->id_DiskState = ID_WRITE_PROTECTED;
3233 else
3234 id->id_DiskState = ID_VALIDATED;
3236 error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
3237 if(error >= 0)
3239 SHOWMSG("got the disk data");
3240 SHOWVALUE(block_size);
3241 SHOWVALUE(num_blocks);
3242 SHOWVALUE(num_blocks_free);
3244 if(block_size <= 0)
3245 block_size = 512;
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;
3271 else
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);
3281 result = DOSFALSE;
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;
3293 RETURN(result);
3294 return(result);
3297 STATIC LONG
3298 Action_Info(
3299 struct FileLock * lock,
3300 struct InfoData * id,
3301 SIPTR * error_ptr)
3303 LONG result;
3305 ENTER();
3307 SHOWVALUE(lock);
3309 if(lock == NULL || lock->fl_Volume != MKBADDR(VolumeNode))
3311 SHOWMSG("volume node does not match");
3313 result = DOSFALSE;
3315 (*error_ptr) = ERROR_NO_DISK;
3317 else
3319 result = Action_DiskInfo(id,error_ptr);
3322 RETURN(result);
3323 return(result);
3326 /****************************************************************************/
3328 STATIC LONG
3329 Action_ExamineObject(
3330 struct FileLock * lock,
3331 struct FileInfoBlock * fib,
3332 SIPTR * error_ptr)
3334 LONG result = DOSFALSE;
3335 LONG error = OK;
3337 ENTER();
3339 SHOWVALUE(lock);
3341 memset(fib,0,sizeof(*fib));
3343 if(lock == NULL)
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;
3351 #else
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;
3357 #endif
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;
3368 else
3370 struct LockNode * ln = (struct LockNode *)lock->fl_Key;
3371 LONG seconds;
3372 smba_stat_t st;
3374 error = smba_getattr(ln->ln_File,&st);
3375 if(error < 0)
3377 SHOWMSG("information not available");
3379 error = MapErrnoToIoErr(error);
3380 goto out;
3383 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3384 if(seconds < 0)
3385 seconds = 0;
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;
3401 #else
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;
3407 #endif
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;
3416 else
3418 STRPTR name;
3419 LONG i;
3421 name = ln->ln_FullName;
3422 for(i = strlen(name)-1 ; i >= 0 ; i--)
3424 if(name[i] == SMB_PATH_SEPARATOR)
3426 name = &name[i+1];
3427 break;
3431 /* Just checking: will the name fit? */
3432 if(strlen(name) >= sizeof(fib->fib_FileName))
3434 error = ERROR_INVALID_COMPONENT_NAME;
3435 goto out;
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;
3448 if(st.is_wp)
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;
3457 if(st.is_system)
3458 fib->fib_Protection |= FIBF_PURE;
3460 if(NOT st.is_dir)
3461 fib->fib_DiskKey = -1;
3465 result = DOSTRUE;
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);
3476 out:
3478 (*error_ptr) = error;
3480 RETURN(result);
3481 return(result);
3484 /****************************************************************************/
3486 STATIC BOOL
3487 NameIsAcceptable(STRPTR name,LONG max_len)
3489 BOOL result = FALSE;
3490 UBYTE c;
3492 /* This takes care of "." and "..". */
3493 if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
3494 goto out;
3496 /* Now for embedded '/', ':' and '\' characters and
3497 * names that just don't want to fit.
3499 while((c = (*name++)) != '\0')
3501 max_len--;
3502 if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
3503 goto out;
3506 result = TRUE;
3508 out:
3510 return(result);
3513 /****************************************************************************/
3515 static int
3516 dir_scan_callback_func_exnext(
3517 struct FileInfoBlock * fib,
3518 int unused_fpos,
3519 int nextpos,
3520 char * name,
3521 int eof,
3522 smba_stat_t * st)
3524 int result;
3526 ENTER();
3528 D((" '%s'",name));
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))
3538 LONG seconds;
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;
3550 if(st->is_wp)
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;
3559 if(st->is_system)
3560 fib->fib_Protection |= FIBF_PURE;
3562 seconds = st->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3563 if(seconds < 0)
3564 seconds = 0;
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;
3570 result = 1;
3572 else
3574 result = 0;
3577 fib->fib_DiskKey = eof ? -1 : nextpos;
3579 RETURN(result);
3580 return(result);
3583 STATIC LONG
3584 Action_ExamineNext(
3585 struct FileLock * lock,
3586 struct FileInfoBlock * fib,
3587 SIPTR * error_ptr)
3589 struct LockNode * ln;
3590 LONG result = DOSFALSE;
3591 LONG error = OK;
3592 long offset;
3593 int count;
3595 ENTER();
3597 SHOWVALUE(lock);
3599 if(fib->fib_DiskKey == -1)
3601 SHOWMSG("scanning finished.");
3602 error = ERROR_NO_MORE_ENTRIES;
3603 goto out;
3606 if(lock == NULL)
3608 SHOWMSG("invalid lock");
3609 error = ERROR_INVALID_LOCK;
3610 goto out;
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)
3623 offset = 0;
3625 ln->ln_RestartExamine = FALSE;
3628 memset(fib,0,sizeof(*fib));
3630 SHOWMSG("calling 'smba_readdir'");
3631 SHOWVALUE(offset);
3633 count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
3635 SHOWVALUE(count);
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;
3643 goto out;
3645 else if (count == (-EIO))
3647 SHOWMSG("ouch! directory read error");
3648 fib->fib_DiskKey = -1;
3650 error = ERROR_NO_DEFAULT_DIR;
3651 goto out;
3653 else if (count < 0)
3655 SHOWMSG("error whilst scanning");
3656 SHOWVALUE(count);
3657 fib->fib_DiskKey = -1;
3659 error = MapErrnoToIoErr(count);
3660 goto out;
3663 result = DOSTRUE;
3665 out:
3667 (*error_ptr) = error;
3669 RETURN(result);
3670 return(result);
3673 /****************************************************************************/
3675 struct ExAllContext
3677 struct ExAllData * ec_Last;
3678 struct ExAllData * ec_Next;
3679 ULONG ec_BytesLeft;
3680 ULONG ec_MinSize;
3681 struct ExAllControl * ec_Control;
3682 ULONG ec_Type;
3683 LONG ec_Error;
3684 BOOL ec_FirstAttempt;
3687 static int
3688 dir_scan_callback_func_exall(
3689 struct ExAllContext * ec,
3690 int unused_fpos,
3691 int nextpos,
3692 char * name,
3693 int eof,
3694 smba_stat_t * st)
3696 int result = 0;
3698 ENTER();
3700 D((" '%s'",name));
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;
3711 ULONG size;
3712 ULONG type = ec->ec_Type;
3713 BOOL take_it;
3715 size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3UL;
3716 SHOWVALUE(size);
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
3723 * really begun.
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;
3731 else
3733 SHOWMSG("try again");
3734 ec->ec_Error = 0;
3737 result = 1;
3738 goto out;
3741 ed = ec->ec_Next;
3743 ed->ed_Next = NULL;
3744 ed->ed_Name = (STRPTR)(((IPTR)ed) + ec->ec_MinSize);
3745 strcpy(ed->ed_Name,name);
3747 TranslateCName(ed->ed_Name,M2A);
3749 if(type >= ED_TYPE)
3750 ed->ed_Type = st->is_dir ? ST_USERDIR : ST_FILE;
3752 if(type >= ED_SIZE)
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;
3760 if(st->is_wp)
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;
3769 if(st->is_system)
3770 ed->ed_Prot |= FIBF_PURE;
3773 if(type >= ED_DATE)
3775 LONG seconds;
3777 seconds = st->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
3778 if(seconds < 0)
3779 seconds = 0;
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;
3792 take_it = TRUE;
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");
3800 take_it = FALSE;
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");
3820 take_it = FALSE;
3824 if(take_it)
3826 SHOWMSG("registering new entry");
3828 if(ec->ec_Last != NULL)
3829 ec->ec_Last->ed_Next = ed;
3831 ec->ec_Last = 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);
3844 out:
3846 ec->ec_FirstAttempt = FALSE;
3848 RETURN(result);
3849 return(result);
3852 STATIC LONG
3853 Action_ExamineAll(
3854 struct FileLock * lock,
3855 struct ExAllData * ed,
3856 ULONG size,
3857 ULONG type,
3858 struct ExAllControl * eac,
3859 SIPTR * error_ptr)
3861 struct ExAllContext ec;
3862 struct LockNode * ln;
3863 LONG result = DOSFALSE;
3864 LONG error = OK;
3865 LONG offset;
3866 int count;
3868 ENTER();
3870 SHOWVALUE(lock);
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;
3880 goto out;
3883 ed->ed_Next = NULL;
3885 if(eac->eac_LastKey == (ULONG)-1)
3887 SHOWMSG("scanning finished.");
3888 error = ERROR_NO_MORE_ENTRIES;
3889 goto out;
3892 if(lock == NULL)
3894 SHOWMSG("invalid lock");
3895 error = ERROR_INVALID_LOCK;
3896 goto out;
3899 if(type < ED_NAME || type > ED_OWNER)
3901 D(("type %ld not supported",type));
3902 error = ERROR_BAD_NUMBER;
3903 goto out;
3906 SHOWVALUE(type);
3908 memset(&ec,0,sizeof(ec));
3910 ec.ec_Next = ed;
3911 ec.ec_BytesLeft = size;
3912 ec.ec_Control = eac;
3913 ec.ec_Type = type;
3914 ec.ec_Error = ERROR_NO_MORE_ENTRIES;
3915 ec.ec_FirstAttempt = TRUE;
3917 switch(type)
3919 case ED_NAME:
3921 ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
3922 break;
3924 case ED_TYPE:
3926 ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
3927 break;
3929 case ED_SIZE:
3931 ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
3932 break;
3934 case ED_PROTECTION:
3936 ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
3937 break;
3939 case ED_DATE:
3941 ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
3942 break;
3944 case ED_COMMENT:
3946 ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
3947 break;
3949 case ED_OWNER:
3951 ec.ec_MinSize = sizeof(struct ExAllData);
3952 break;
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)
3967 offset = 0;
3969 ln->ln_RestartExamine = FALSE;
3972 if(offset == 0)
3974 smba_stat_t st;
3976 SHOWMSG("first invocation");
3978 SHOWMSG("getting file attributes");
3979 error = smba_getattr(ln->ln_File,&st);
3980 if(error < 0)
3982 SHOWMSG("didn't work");
3983 error = MapErrnoToIoErr(error);
3984 eac->eac_LastKey = (ULONG)-1;
3985 goto out;
3988 if(NOT st.is_dir)
3990 SHOWMSG("lock does not refer to a directory");
3991 error = ERROR_OBJECT_WRONG_TYPE;
3992 eac->eac_LastKey = (ULONG)-1;
3993 goto out;
3997 SHOWMSG("calling 'smba_readdir'");
3998 SHOWVALUE(offset);
4000 count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
4002 SHOWVALUE(count);
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;
4015 goto out;
4017 else if (count == (-EIO))
4019 SHOWMSG("ouch! directory read error");
4020 eac->eac_LastKey = (ULONG)-1;
4022 error = ERROR_NO_DEFAULT_DIR;
4023 goto out;
4025 else if (count < 0)
4027 SHOWMSG("error whilst scanning");
4028 eac->eac_LastKey = (ULONG)-1;
4030 error = MapErrnoToIoErr(count);
4031 goto out;
4034 SHOWMSG("ok");
4035 result = DOSTRUE;
4037 out:
4039 #if DEBUG
4041 SHOWVALUE(eac->eac_Entries);
4043 while(ed != NULL)
4045 SHOWSTRING(ed->ed_Name);
4047 ed = ed->ed_Next;
4050 #endif /* DEBUG */
4052 (*error_ptr) = error;
4054 RETURN(result);
4055 return(result);
4058 /****************************************************************************/
4060 STATIC LONG
4061 Action_Find(
4062 LONG action,
4063 struct FileHandle * fh,
4064 struct FileLock * parent,
4065 APTR bcpl_name,
4066 SIPTR * error_ptr)
4068 LONG result = DOSFALSE;
4069 STRPTR parent_path = NULL;
4070 STRPTR full_name = NULL;
4071 LONG full_name_size;
4072 struct FileNode * fn = NULL;
4073 STRPTR parent_name;
4074 UBYTE name[MAX_FILENAME_LEN];
4075 BOOL file_exists = FALSE;
4076 BOOL create_new_file;
4077 smba_file_t * file = NULL;
4078 smba_stat_t st;
4079 LONG error;
4081 ENTER();
4083 switch(action)
4085 case ACTION_FINDINPUT:
4086 D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
4087 break;
4089 case ACTION_FINDOUTPUT:
4090 D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
4091 break;
4093 case ACTION_FINDUPDATE:
4094 D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
4095 break;
4098 SHOWVALUE(parent);
4100 if(parent != NULL)
4102 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
4104 parent_name = ln->ln_FullName;
4106 else
4108 parent_name = NULL;
4111 ConvertBString(sizeof(name),name,bcpl_name);
4112 TranslateCName(name,A2M);
4114 if(IsReservedName(FilePart(name)))
4116 error = ERROR_OBJECT_NOT_FOUND;
4117 goto out;
4120 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
4121 if(error != OK)
4122 goto out;
4124 /* Trying to open the root directory? */
4125 if(full_name == NULL)
4127 error = ERROR_OBJECT_WRONG_TYPE;
4128 goto out;
4131 fn = AllocateMemory(sizeof(*fn));
4132 if(fn == NULL)
4134 error = ERROR_NO_FREE_STORE;
4135 goto out;
4138 memset(fn,0,sizeof(*fn));
4140 fn->fn_Handle = fh;
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);
4145 if(error != OK)
4146 goto out;
4148 SHOWSTRING(full_name);
4150 if(smba_open(ServerData,full_name,full_name_size,&file) == OK &&
4151 smba_getattr(file,&st) == OK)
4153 file_exists = TRUE;
4154 if(st.is_dir)
4156 error = ERROR_OBJECT_WRONG_TYPE;
4157 goto out;
4160 if(file != NULL)
4161 smba_close(file);
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)
4175 if(file_exists)
4177 /* File apparently opens Ok and information on it
4178 * is available, don't try to replace it.
4180 create_new_file = FALSE;
4182 else
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;
4193 else
4195 /* What's that? */
4196 error = ERROR_ACTION_NOT_KNOWN;
4197 goto out;
4200 /* Create a new file? */
4201 if(create_new_file)
4203 smba_file_t * dir;
4204 STRPTR base_name;
4205 LONG i;
4207 if(WriteProtected)
4209 error = ERROR_DISK_WRITE_PROTECTED;
4210 goto out;
4213 parent_path = AllocateMemory(strlen(full_name)+3);
4214 if(parent_path == NULL)
4216 error = ERROR_NO_FREE_STORE;
4217 goto out;
4220 strcpy(parent_path,full_name);
4221 base_name = NULL;
4222 for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
4224 if(parent_path[i] == SMB_PATH_SEPARATOR)
4226 if(i == 0)
4228 memmove(&parent_path[1],&parent_path[0],strlen(parent_path)+1);
4229 i++;
4232 parent_path[i] = '\0';
4234 base_name = &parent_path[i+1];
4235 break;
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);
4243 if(error < 0)
4245 error = MapErrnoToIoErr(error);
4246 goto out;
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);
4256 if(error < 0)
4258 SHOWMSG("didn't work.");
4259 SHOWVALUE(error);
4261 smba_close(dir);
4262 error = MapErrnoToIoErr(error);
4264 SHOWVALUE(error);
4266 goto out;
4269 SHOWMSG("good.");
4271 smba_close(dir);
4274 /* Now for the remainder... */
4275 error = smba_open(ServerData,full_name,full_name_size,&fn->fn_File);
4276 if(error < 0)
4278 error = MapErrnoToIoErr(error);
4279 goto out;
4282 fh->fh_Arg1 = (IPTR)fn;
4284 AddTail((struct List *)&FileList,(struct Node *)fn);
4285 result = DOSTRUE;
4287 out:
4289 if(result == DOSFALSE)
4291 FreeMemory(full_name);
4292 FreeMemory(fn);
4295 FreeMemory(parent_path);
4297 (*error_ptr) = error;
4299 RETURN(result);
4300 return(result);
4303 /****************************************************************************/
4305 STATIC LONG
4306 Action_Read(
4307 struct FileNode * fn,
4308 APTR mem,
4309 LONG length,
4310 SIPTR * error_ptr)
4312 LONG result = 0;
4313 LONG error = OK;
4315 ENTER();
4317 if(length > 0)
4319 result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
4320 if(result < 0)
4322 error = MapErrnoToIoErr(result);
4323 result = -1;
4324 goto out;
4327 fn->fn_Offset += result;
4330 out:
4332 (*error_ptr) = error;
4334 RETURN(result);
4335 return(result);
4338 /****************************************************************************/
4340 STATIC LONG
4341 Action_Write(
4342 struct FileNode * fn,
4343 APTR mem,
4344 LONG length,
4345 SIPTR * error_ptr)
4347 LONG result = DOSFALSE;
4348 LONG error = OK;
4350 ENTER();
4352 if(WriteProtected)
4354 error = ERROR_DISK_WRITE_PROTECTED;
4355 goto out;
4358 if(length > 0)
4360 result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
4361 if(result < 0)
4363 error = MapErrnoToIoErr(result);
4364 result = -1;
4365 goto out;
4368 fn->fn_Offset += result;
4371 out:
4373 (*error_ptr) = error;
4375 RETURN(result);
4376 return(result);
4379 /****************************************************************************/
4381 STATIC LONG
4382 Action_End(
4383 struct FileNode * fn,
4384 SIPTR * error_ptr)
4386 Remove((struct Node *)fn);
4388 smba_close(fn->fn_File);
4389 FreeMemory(fn->fn_FullName);
4390 FreeMemory(fn);
4392 (*error_ptr) = OK;
4393 return(DOSTRUE);
4396 /****************************************************************************/
4398 STATIC LONG
4399 Action_Seek(
4400 struct FileNode * fn,
4401 LONG position,
4402 LONG mode,
4403 SIPTR * error_ptr)
4405 LONG previous_position = fn->fn_Offset;
4406 LONG result = -1;
4407 LONG offset;
4408 LONG error;
4410 ENTER();
4412 /* olsen: This doesn't really work with Microsoft SMB servers, but it works with Samba. */
4413 #if 0
4415 switch(mode)
4417 case OFFSET_BEGINNING:
4419 mode = 0;
4420 break;
4422 case OFFSET_CURRENT:
4424 mode = 1;
4425 break;
4427 case OFFSET_END:
4429 mode = 2;
4430 break;
4432 default:
4434 error = ERROR_ACTION_NOT_KNOWN;
4435 goto out;
4438 error = smba_seek (fn->fn_File, position, mode, (off_t *) &offset);
4439 if(error < 0)
4441 error = MapErrnoToIoErr(error);
4442 goto out;
4445 #endif
4447 /* olsen: This is the original implementation. */
4448 #if 0
4450 smba_stat_t st;
4452 error = smba_getattr(fn->fn_File,&st);
4453 if(error < 0)
4455 error = MapErrnoToIoErr(error);
4456 goto out;
4459 offset = fn->fn_Offset;
4461 switch(mode)
4463 case OFFSET_BEGINNING:
4465 offset = position;
4466 break;
4468 case OFFSET_CURRENT:
4470 offset += position;
4471 break;
4473 case OFFSET_END:
4475 offset = st.size + position;
4476 break;
4478 default:
4480 error = ERROR_ACTION_NOT_KNOWN;
4481 goto out;
4484 if(offset < 0 || offset > st.size)
4486 error = ERROR_SEEK_ERROR;
4487 goto out;
4490 #endif
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
4496 * here...
4498 #if 1
4500 smba_stat_t st;
4502 switch(mode)
4504 case OFFSET_BEGINNING:
4506 offset = position;
4507 break;
4509 case OFFSET_CURRENT:
4511 offset = fn->fn_Offset + position;
4512 break;
4514 case OFFSET_END:
4516 error = smba_getattr(fn->fn_File,&st);
4517 if(error < 0)
4519 error = MapErrnoToIoErr(error);
4520 goto out;
4523 offset = st.size + position;
4524 break;
4526 default:
4528 error = ERROR_ACTION_NOT_KNOWN;
4529 goto out;
4532 if(offset < 0)
4534 error = ERROR_SEEK_ERROR;
4535 goto out;
4538 error = smba_seek (fn->fn_File, offset, 0, (off_t *) &offset);
4539 if(error < 0)
4541 error = MapErrnoToIoErr(error);
4542 goto out;
4545 #endif
4547 error = OK;
4549 fn->fn_Offset = offset;
4551 result = previous_position;
4553 out:
4555 (*error_ptr) = error;
4557 RETURN(result);
4558 return(result);
4561 /****************************************************************************/
4563 STATIC LONG
4564 Action_SetFileSize(
4565 struct FileNode * fn,
4566 LONG position,
4567 LONG mode,
4568 SIPTR * error_ptr)
4570 smba_stat_t st;
4571 LONG result = -1;
4572 LONG error;
4573 long offset;
4575 ENTER();
4577 if(WriteProtected)
4579 error = ERROR_DISK_WRITE_PROTECTED;
4580 goto out;
4583 error = smba_getattr(fn->fn_File,&st);
4584 if(error < 0)
4586 error = MapErrnoToIoErr(error);
4587 goto out;
4590 offset = fn->fn_Offset;
4592 switch(mode)
4594 case OFFSET_BEGINNING:
4596 offset = position;
4597 break;
4599 case OFFSET_CURRENT:
4601 offset += position;
4602 break;
4604 case OFFSET_END:
4606 offset = st.size + position;
4607 break;
4609 default:
4611 error = ERROR_ACTION_NOT_KNOWN;
4612 goto out;
4615 if(offset < 0)
4617 error = ERROR_SEEK_ERROR;
4618 goto out;
4621 st.atime = -1;
4622 st.ctime = -1;
4623 st.mtime = -1;
4624 st.size = offset;
4626 error = smba_setattr(fn->fn_File,&st);
4627 if(error < 0)
4629 error = MapErrnoToIoErr(error);
4630 goto out;
4633 if(fn->fn_Offset > offset)
4634 fn->fn_Offset = offset;
4636 result = offset;
4638 out:
4640 (*error_ptr) = error;
4642 RETURN(result);
4643 return(result);
4646 /****************************************************************************/
4648 STATIC LONG
4649 Action_SetDate(
4650 struct FileLock * parent,
4651 APTR bcpl_name,
4652 struct DateStamp * ds,
4653 SIPTR * error_ptr)
4655 LONG result = DOSFALSE;
4656 STRPTR full_name = NULL;
4657 LONG full_name_size;
4658 smba_file_t * file = NULL;
4659 STRPTR parent_name;
4660 UBYTE name[MAX_FILENAME_LEN];
4661 smba_stat_t st;
4662 LONG seconds;
4663 LONG error;
4665 ENTER();
4667 if(WriteProtected)
4669 error = ERROR_DISK_WRITE_PROTECTED;
4670 goto out;
4673 SHOWVALUE(parent);
4675 if(parent != NULL)
4677 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
4679 parent_name = ln->ln_FullName;
4681 else
4683 parent_name = NULL;
4686 ConvertBString(sizeof(name),name,bcpl_name);
4687 TranslateCName(name,A2M);
4689 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
4690 if(error != OK)
4691 goto out;
4693 /* Trying to change the date of the root directory? */
4694 if(full_name == NULL)
4696 error = ERROR_OBJECT_IN_USE;
4697 goto out;
4700 SHOWSTRING(full_name);
4702 error = smba_open(ServerData,full_name,full_name_size,&file);
4703 if(error < 0)
4705 error = MapErrnoToIoErr(error);
4706 goto out;
4709 error = smba_getattr(file,&st);
4710 if(error < 0)
4712 error = MapErrnoToIoErr(error);
4713 goto out;
4716 seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
4718 st.atime = -1;
4719 st.ctime = -1;
4720 st.mtime = seconds + UNIX_TIME_OFFSET + GetTimeZoneDelta();
4721 st.size = -1;
4723 error = smba_setattr(file,&st);
4724 if(error < 0)
4726 error = MapErrnoToIoErr(error);
4727 goto out;
4730 result = DOSTRUE;
4732 out:
4734 FreeMemory(full_name);
4735 if(file != NULL)
4736 smba_close(file);
4738 (*error_ptr) = error;
4740 RETURN(result);
4741 return(result);
4744 /****************************************************************************/
4746 STATIC LONG
4747 Action_ExamineFH(
4748 struct FileNode * fn,
4749 struct FileInfoBlock * fib,
4750 SIPTR * error_ptr)
4752 LONG result = DOSFALSE;
4753 smba_stat_t st;
4754 LONG error;
4755 LONG seconds;
4756 STRPTR name;
4757 LONG i;
4759 ENTER();
4761 error = smba_getattr(fn->fn_File,&st);
4762 if(error < 0)
4764 error = MapErrnoToIoErr(error);
4765 goto out;
4768 name = fn->fn_FullName;
4769 for(i = strlen(name)-1 ; i >= 0 ; i--)
4771 if(name[i] == SMB_PATH_SEPARATOR)
4773 name = &name[i+1];
4774 break;
4778 /* Just checking: will the name fit? */
4779 if(strlen(name) >= sizeof(fib->fib_FileName))
4781 error = ERROR_INVALID_COMPONENT_NAME;
4782 goto out;
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;
4799 if(st.is_wp)
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;
4808 if(st.is_system)
4809 fib->fib_Protection |= FIBF_PURE;
4811 seconds = st.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
4812 if(seconds < 0)
4813 seconds = 0;
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;
4819 result = DOSTRUE;
4821 out:
4823 (*error_ptr) = error;
4825 RETURN(result);
4826 return(result);
4829 /****************************************************************************/
4831 STATIC BPTR
4832 Action_ParentFH(
4833 struct FileNode * fn,
4834 SIPTR * error_ptr)
4836 BPTR result = ZERO;
4837 struct LockNode * ln = NULL;
4838 LONG error;
4839 STRPTR full_name;
4840 LONG full_name_size;
4841 LONG i;
4843 ENTER();
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;
4853 goto out;
4856 strcpy(full_name,fn->fn_FullName);
4858 for(i = strlen(full_name)-1 ; i >= 0 ; i--)
4860 if(i == 0)
4862 strcpy(full_name,SMB_ROOT_DIR_NAME);
4863 break;
4865 else if (full_name[i] == SMB_PATH_SEPARATOR)
4867 full_name[i] = '\0';
4868 break;
4872 ln = AllocateMemory(sizeof(*ln));
4873 if(ln == NULL)
4875 error = ERROR_NO_FREE_STORE;
4876 goto out;
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);
4890 if(error < 0)
4892 error = MapErrnoToIoErr(error);
4893 goto out;
4896 AddTail((struct List *)&LockList,(struct Node *)ln);
4897 result = MKBADDR(&ln->ln_FileLock);
4898 SHOWVALUE(&ln->ln_FileLock);
4900 out:
4902 if(result == ZERO)
4904 FreeMemory(ln);
4905 FreeMemory(full_name);
4908 (*error_ptr) = error;
4910 RETURN(result);
4911 return(result);
4914 /****************************************************************************/
4916 STATIC BPTR
4917 Action_CopyDirFH(
4918 struct FileNode * fn,
4919 SIPTR * error_ptr)
4921 BPTR result = ZERO;
4922 struct LockNode * ln = NULL;
4923 STRPTR full_name = NULL;
4924 LONG full_name_size;
4925 LONG error;
4927 ENTER();
4929 if(fn->fn_Mode != SHARED_LOCK)
4931 error = ERROR_OBJECT_IN_USE;
4932 goto out;
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;
4943 goto out;
4946 strcpy(full_name,fn->fn_FullName);
4948 ln = AllocateMemory(sizeof(*ln));
4949 if(ln == NULL)
4951 error = ERROR_NO_FREE_STORE;
4952 goto out;
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);
4966 if(error < 0)
4968 error = MapErrnoToIoErr(error);
4969 goto out;
4972 AddTail((struct List *)&LockList,(struct Node *)ln);
4973 result = MKBADDR(&ln->ln_FileLock);
4974 SHOWVALUE(&ln->ln_FileLock);
4976 out:
4978 if(result == ZERO)
4980 FreeMemory(ln);
4981 FreeMemory(full_name);
4984 (*error_ptr) = error;
4986 RETURN(result);
4987 return(result);
4990 /****************************************************************************/
4992 STATIC LONG
4993 Action_FHFromLock(
4994 struct FileHandle * fh,
4995 struct FileLock * fl,
4996 SIPTR * error_ptr)
4998 LONG result = DOSFALSE;
4999 struct FileNode * fn;
5000 struct LockNode * ln;
5001 LONG error = OK;
5003 ENTER();
5005 SHOWVALUE(fl);
5007 fn = AllocateMemory(sizeof(*fn));
5008 if(fn == NULL)
5010 error = ERROR_NO_FREE_STORE;
5011 goto out;
5014 memset(fn,0,sizeof(*fn));
5016 ln = (struct LockNode *)fl->fl_Key;
5018 fn->fn_Handle = fh;
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);
5024 FreeMemory(ln);
5026 fh->fh_Arg1 = (IPTR)fn;
5028 AddTail((struct List *)&FileList,(struct Node *)fn);
5029 result = DOSTRUE;
5031 out:
5033 (*error_ptr) = error;
5035 RETURN(result);
5036 return(result);
5039 /****************************************************************************/
5041 STATIC LONG
5042 Action_RenameDisk(
5043 APTR bcpl_name,
5044 SIPTR * error_ptr)
5046 LONG result = DOSFALSE;
5047 LONG error = OK;
5048 STRPTR old_name;
5049 STRPTR new_name;
5050 UBYTE * name;
5051 LONG len;
5053 ENTER();
5055 if(NOT VolumeNodeAdded)
5057 error = ERROR_OBJECT_IN_USE;
5058 goto out;
5061 if(WriteProtected)
5063 error = ERROR_DISK_WRITE_PROTECTED;
5064 goto out;
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().
5072 name = bcpl_name;
5074 len = name[0];
5076 new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
5077 if(new_name == NULL)
5079 error = ERROR_NO_FREE_STORE;
5080 goto out;
5083 new_name[0] = len;
5084 memcpy(&new_name[1],&name[1],len);
5085 new_name[len+1] = '\0';
5087 Forbid();
5089 old_name = BADDR(VolumeNode->dol_Name);
5090 VolumeNode->dol_Name = MKBADDR(new_name);
5092 Permit();
5094 FreeVec(old_name);
5096 SendDiskChange(IECLASS_DISKINSERTED);
5098 result = DOSTRUE;
5100 out:
5102 (*error_ptr) = error;
5104 RETURN(result);
5105 return(result);
5108 /****************************************************************************/
5110 STATIC LONG
5111 Action_ChangeMode(
5112 LONG type,
5113 APTR object,
5114 LONG new_mode,
5115 SIPTR * error_ptr)
5117 LONG result = DOSFALSE;
5118 struct FileLock * fl = NULL;
5119 struct FileNode * fn = NULL;
5120 struct LockNode * ln = NULL;
5121 STRPTR name;
5122 LONG old_mode;
5123 LONG error = OK;
5125 ENTER();
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;
5132 goto out;
5135 /* Now obtain the data structures, name and mode
5136 * associated with the object in question.
5138 if(type == CHANGE_LOCK)
5140 fl = object;
5141 ln = (struct LockNode *)fl->fl_Key;
5142 name = ln->ln_FullName;
5143 old_mode = fl->fl_Access;
5145 else
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)
5157 result = DOSTRUE;
5158 goto out;
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
5166 * value.
5168 if(new_mode == SHARED_LOCK)
5170 if(type == CHANGE_LOCK)
5171 fl->fl_Access = new_mode;
5172 else
5173 fn->fn_Mode = new_mode;
5175 result = DOSTRUE;
5176 goto out;
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;
5185 goto out;
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;
5194 goto out;
5197 /* There is just one single reference
5198 * to this object; change the mode
5199 * and quit.
5201 if(type == CHANGE_LOCK)
5202 fl->fl_Access = new_mode;
5203 else
5204 fn->fn_Mode = new_mode;
5206 result = DOSTRUE;
5208 out:
5210 (*error_ptr) = error;
5212 RETURN(result);
5213 return(result);
5216 /****************************************************************************/
5218 STATIC LONG
5219 Action_WriteProtect(
5220 LONG flag,
5221 ULONG key,
5222 SIPTR * error_ptr)
5224 LONG result = DOSFALSE;
5225 LONG error = OK;
5227 ENTER();
5229 if(flag == DOSFALSE)
5231 if(WriteProtected)
5233 if(key != WriteProtectKey)
5235 error = ERROR_INVALID_LOCK;
5236 goto out;
5239 WriteProtected = FALSE;
5241 if(VolumeNodeAdded)
5243 SendDiskChange(IECLASS_DISKREMOVED);
5244 SendDiskChange(IECLASS_DISKINSERTED);
5248 else
5250 if(NOT WriteProtected)
5252 WriteProtected = TRUE;
5253 WriteProtectKey = key;
5255 if(VolumeNodeAdded)
5257 SendDiskChange(IECLASS_DISKREMOVED);
5258 SendDiskChange(IECLASS_DISKINSERTED);
5261 else
5263 error = ERROR_INVALID_LOCK;
5264 goto out;
5268 result = DOSTRUE;
5270 out:
5272 (*error_ptr) = error;
5274 RETURN(result);
5275 return(result);
5278 /****************************************************************************/
5280 STATIC LONG
5281 Action_MoreCache(
5282 LONG buffer_delta,
5283 SIPTR * error_ptr)
5285 LONG result;
5286 int old_size;
5288 ENTER();
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)
5296 result = DOSFALSE;
5297 (*error_ptr) = ERROR_NO_FREE_STORE;
5300 RETURN(result);
5301 return(result);
5304 /****************************************************************************/
5306 STATIC LONG
5307 Action_SetComment(
5308 struct FileLock * parent,
5309 APTR bcpl_name,
5310 APTR bcpl_comment,
5311 SIPTR * error_ptr)
5313 LONG result = DOSFALSE;
5314 STRPTR full_name = NULL;
5315 LONG full_name_size;
5316 smba_file_t * file = NULL;
5317 STRPTR parent_name;
5318 UBYTE name[MAX_FILENAME_LEN];
5319 UBYTE comment[80];
5320 LONG error;
5322 ENTER();
5324 if(WriteProtected)
5326 error = ERROR_DISK_WRITE_PROTECTED;
5327 goto out;
5330 SHOWVALUE(parent);
5332 if(parent != NULL)
5334 struct LockNode * ln = (struct LockNode *)parent->fl_Key;
5336 parent_name = ln->ln_FullName;
5338 else
5340 parent_name = NULL;
5343 ConvertBString(sizeof(name),name,bcpl_name);
5344 TranslateCName(name,A2M);
5346 error = BuildFullName(parent_name,name,&full_name,&full_name_size);
5347 if(error != OK)
5348 goto out;
5350 /* Trying to change the comment of the root directory? */
5351 if(full_name == NULL)
5353 error = ERROR_OBJECT_IN_USE;
5354 goto out;
5357 SHOWSTRING(full_name);
5359 error = smba_open(ServerData,full_name,full_name_size,&file);
5360 if(error < 0)
5362 error = MapErrnoToIoErr(error);
5363 goto out;
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;
5374 goto out;
5377 result = DOSTRUE;
5379 out:
5381 FreeMemory(full_name);
5382 if(file != NULL)
5383 smba_close(file);
5385 (*error_ptr) = error;
5387 RETURN(result);
5388 return(result);
5391 /****************************************************************************/
5393 STATIC LONG
5394 Action_LockRecord (
5395 struct FileNode * fn,
5396 LONG offset,
5397 LONG length,
5398 LONG mode,
5399 ULONG timeout,
5400 SIPTR * error_ptr)
5402 LONG result = DOSFALSE;
5403 LONG error;
5404 LONG umode;
5406 /* Sanity checks... */
5407 if (mode < REC_EXCLUSIVE || mode > REC_SHARED_IMMED)
5409 error = ERROR_ACTION_NOT_KNOWN;
5410 goto out;
5413 /* Invalid offset, size or integer overflow? */
5414 if (offset < 0 || length <= 0 || offset + length < offset)
5416 error = ERROR_LOCK_COLLISION;
5417 goto out;
5420 if ((mode == REC_SHARED) || (mode == REC_SHARED_IMMED))
5421 umode = 1;
5422 else
5423 umode = 0;
5425 if ((mode == REC_SHARED_IMMED) || (mode == REC_EXCLUSIVE_IMMED))
5426 timeout = 0;
5428 if (timeout > 0)
5430 if (timeout > 214748364)
5431 timeout = ~0; /* wait forever */
5432 else
5433 timeout *= 20; /* milliseconds instead of Ticks */
5436 error = smba_lockrec (fn->fn_File, offset, length, umode, 0, (long)timeout);
5437 if(error < 0)
5439 error = MapErrnoToIoErr(error);
5440 goto out;
5443 result = DOSTRUE;
5445 out:
5447 (*error_ptr) = error;
5449 RETURN(result);
5450 return(result);
5453 /****************************************************************************/
5455 STATIC LONG
5456 Action_FreeRecord (
5457 struct FileNode * fn,
5458 LONG offset,
5459 LONG length,
5460 SIPTR * error_ptr)
5462 LONG result = DOSFALSE;
5463 LONG error;
5465 /* Sanity checks... */
5466 if(offset < 0 || length <= 0 || offset + length < offset)
5468 error = ERROR_RECORD_NOT_LOCKED;
5469 goto out;
5472 error = smba_lockrec (fn->fn_File, offset, length, 2, -1, 0);
5473 if (error < 0)
5475 error = MapErrnoToIoErr(error);
5476 goto out;
5479 result = DOSTRUE;
5481 out:
5483 (*error_ptr) = error;
5485 RETURN(result);
5486 return(result);
5489 /****************************************************************************/
5491 STATIC VOID
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);
5500 TimerActive = TRUE;
5503 /****************************************************************************/
5505 STATIC VOID
5506 HandleFileSystem(VOID)
5508 BOOL sign_off = FALSE;
5509 ULONG signals;
5510 BOOL done;
5512 ENTER();
5514 DisplayErrorList();
5515 Quiet = TRUE;
5516 done = 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;
5526 SIPTR res1,res2;
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));
5534 res2 = 0;
5537 if (mn->mn_Node.ln_Type == NT_REPLYMSG)
5539 TimerActive = FALSE;
5540 AddVolume(
5541 args.Service,
5542 args.Workgroup,
5543 args.UserName,
5544 args.Password,
5545 args.ClientName,
5546 args.ServerName,
5547 (args.CacheSize != NULL) ? *args.CacheSize : 0,
5548 args.DeviceName,
5549 args.VolumeName);
5550 continue;
5552 if(!VolumeNodeAdded && dp->dp_Action != ACTION_STARTUP)
5554 res1 = DOSFALSE;
5555 res2 = ERROR_NO_DISK;
5556 ReplyPkt(dp,res1,res2);
5557 continue;
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);
5567 if(!res1)
5568 Quit = TRUE;
5569 break;
5571 case ACTION_DIE:
5573 SHOWMSG("ACTION_DIE");
5574 if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
5576 SHOWMSG("no locks or files pending; quitting");
5578 res1 = DOSTRUE;
5580 else
5582 SHOWMSG("locks or files still pending; cannot quit yet");
5584 res1 = DOSFALSE;
5585 res2 = ERROR_OBJECT_IN_USE;
5588 Quit = TRUE;
5589 break;
5591 case ACTION_CURRENT_VOLUME:
5592 /* (Ignore) -> VolumeNode */
5594 res1 = (IPTR)MKBADDR(VolumeNode);
5595 break;
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);
5601 break;
5603 case ACTION_RENAME_DISK:
5604 /* Name -> Bool */
5606 res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
5607 break;
5609 case ACTION_FREE_LOCK:
5610 /* Lock -> Bool */
5612 res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
5613 break;
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);
5619 break;
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);
5627 break;
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);
5647 break;
5649 case ACTION_COPY_DIR:
5650 /* Lock -> Lock */
5652 res1 = (IPTR)Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
5653 break;
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);
5659 break;
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);
5665 break;
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);
5671 break;
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);
5677 break;
5679 case ACTION_DISK_INFO:
5680 /* InfoData -> Bool */
5682 Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
5683 res1 = DOSTRUE;
5684 res2 = 0;
5685 break;
5687 case ACTION_INFO:
5688 /* FileLock,InfoData -> Bool */
5690 res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
5691 break;
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);
5697 break;
5699 case ACTION_PARENT:
5700 /* Lock -> Lock */
5702 res1 = (IPTR)Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
5703 break;
5705 case ACTION_INHIBIT:
5707 SHOWMSG("ACTION_INHIBIT");
5708 res1 = DOSTRUE;
5709 break;
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);
5715 break;
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);
5721 break;
5723 case ACTION_READ:
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);
5727 break;
5729 case ACTION_WRITE:
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);
5733 break;
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);
5741 break;
5743 case ACTION_END:
5744 /* FileHandle->fh_Arg1 -> Bool */
5746 res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
5747 break;
5749 case ACTION_SEEK:
5750 /* FileHandle->fh_Arg1,Position,Mode -> Position */
5752 res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
5753 break;
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);
5759 break;
5761 case ACTION_WRITE_PROTECT:
5762 /* Flag,Key -> Bool */
5764 res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
5765 break;
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);
5771 break;
5773 case ACTION_IS_FILESYSTEM:
5775 SHOWMSG("ACTION_IS_FILESYSTEM");
5776 res1 = DOSTRUE;
5777 break;
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);
5783 break;
5785 case ACTION_COPY_DIR_FH:
5786 /* FileHandle->fh_Arg1 -> Bool */
5788 res1 = (IPTR)Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
5789 break;
5791 case ACTION_PARENT_FH:
5792 /* FileHandle->fh_Arg1 -> Bool */
5794 res1 = (IPTR)Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
5795 break;
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);
5803 break;
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);
5809 break;
5811 case ACTION_EXAMINE_ALL_END:
5812 /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
5814 res1 = DOSTRUE;
5815 break;
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);
5820 break;
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);
5825 break;
5827 default:
5829 D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
5831 res1 = DOSFALSE;
5832 res2 = ERROR_ACTION_NOT_KNOWN;
5834 break;
5837 SHOWVALUE(res1);
5838 SHOWVALUE(res2);
5840 ReplyPkt(dp,res1,res2);
5842 D(("\n"));
5846 #if DEBUG
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));
5861 D((""));
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));
5872 D((""));
5876 #endif /* DEBUG */
5878 if(signals & SIGBREAKF_CTRL_C)
5879 Quit = TRUE;
5881 if(Quit)
5883 if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
5885 SHOWMSG("no locks or files pending; quitting");
5886 done = TRUE;
5888 else
5890 SHOWMSG("locks or files still pending; cannot quit yet");
5894 while(NOT done);
5896 if(sign_off)
5897 LocalPrintf("stopped.\n");
5899 LEAVE();
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.
5909 size_t
5910 strlcpy(char *dst, const char *src, size_t siz)
5912 char *d = dst;
5913 const char *s = src;
5914 size_t n = siz;
5915 size_t result;
5917 /* Copy as many bytes as will fit */
5918 if(n != 0 && --n != 0)
5922 if(((*d++) = (*s++)) == '\0')
5923 break;
5925 while(--n != 0);
5928 /* Not enough room in dst, add NUL and traverse rest of src */
5929 if(n == 0)
5931 if(siz != 0)
5932 (*d) = '\0'; /* NUL-terminate dst */
5934 while((*s++) != '\0')
5938 result = s - src - 1; /* count does not include NUL */
5940 return(result);
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.
5950 size_t
5951 strlcat(char *dst, const char *src, size_t siz)
5953 char *d = dst;
5954 const char *s = src;
5955 size_t n = siz;
5956 size_t dlen;
5957 size_t result;
5959 /* Find the end of dst and adjust bytes left but don't go past end */
5960 while(n-- != 0 && (*d) != '\0')
5961 d++;
5963 dlen = d - dst;
5964 n = siz - dlen;
5966 if(n == 0)
5968 result = dlen + strlen(s);
5970 else
5972 while((*s) != '\0')
5974 if(n != 1)
5976 (*d++) = (*s);
5977 n--;
5980 s++;
5983 (*d) = '\0';
5985 result = dlen + (s - src); /* count does not include NUL */
5988 return(result);