configure configure.in: Added tests for fseek64 and ftell64.
[kai/samba.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba system utilities
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 /*
27    The idea is that this file will eventually have wrappers around all
28    important system calls in samba. The aims are:
29
30    - to enable easier porting by putting OS dependent stuff in here
31
32    - to allow for hooks into other "pseudo-filesystems"
33
34    - to allow easier integration of things like the japanese extensions
35
36    - to support the philosophy of Samba to expose the features of
37      the OS within the SMB model. In general whatever file/printer/variable
38      expansions/etc make sense to the OS should be acceptable to Samba.
39 */
40
41
42 /*******************************************************************
43 this replaces the normal select() system call
44 return if some data has arrived on one of the file descriptors
45 return -1 means error
46 ********************************************************************/
47 #ifndef HAVE_SELECT
48 static int pollfd(int fd)
49 {
50   int     r=0;
51
52 #ifdef HAS_RDCHK
53   r = rdchk(fd);
54 #elif defined(TCRDCHK)
55   (void)ioctl(fd, TCRDCHK, &r);
56 #else
57   (void)ioctl(fd, FIONREAD, &r);
58 #endif
59
60   return(r);
61 }
62
63 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
64 {
65   fd_set fds2;
66   int counter=0;
67   int found=0;
68
69   FD_ZERO(&fds2);
70
71   while (1) 
72   {
73     int i;
74     for (i=0;i<maxfd;i++) {
75       if (FD_ISSET(i,fds) && pollfd(i)>0) {
76         found++;
77         FD_SET(i,&fds2);
78       }
79     }
80
81     if (found) {
82       memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
83       return(found);
84     }
85       
86     if (tval && tval->tv_sec < counter) return(0);
87       sleep(1);
88       counter++;
89   }
90 }
91
92 #else /* !NO_SELECT */
93 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
94 {
95 #ifdef USE_POLL
96   struct pollfd pfd[256];
97   int i;
98   int maxpoll;
99   int timeout;
100   int pollrtn;
101
102   maxpoll = 0;
103   for( i = 0; i < maxfd; i++) {
104     if(FD_ISSET(i,fds)) {
105       struct pollfd *pfdp = &pfd[maxpoll++];
106       pfdp->fd = i;
107       pfdp->events = POLLIN;
108       pfdp->revents = 0;
109     }
110   }
111
112   timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
113                 -1;
114   errno = 0;
115   do {
116     pollrtn = poll( &pfd[0], maxpoll, timeout);
117   } while (pollrtn<0 && errno == EINTR);
118
119   FD_ZERO(fds);
120
121   for( i = 0; i < maxpoll; i++)
122     if( pfd[i].revents & POLLIN )
123       FD_SET(pfd[i].fd,fds);
124
125   return pollrtn;
126 #else /* USE_POLL */
127
128   struct timeval t2;
129   int selrtn;
130
131   do {
132     if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
133     errno = 0;
134     selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
135   } while (selrtn<0 && errno == EINTR);
136
137   return(selrtn);
138 }
139 #endif /* USE_POLL */
140 #endif /* NO_SELECT */
141
142 /*******************************************************************
143 A stat() wrapper that will deal with 64 bit filesizes.
144 ********************************************************************/
145
146 int sys_stat(char *fname,SMB_STRUCT_STAT *sbuf)
147 {
148 #if defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
149   return stat64(fname, sbuf);
150 #else
151   return stat(fname, sbuf);
152 #endif
153 }
154
155 /*******************************************************************
156  An fstat() wrapper that will deal with 64 bit filesizes.
157 ********************************************************************/
158
159 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
160 {
161 #if defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
162   return fstat64(fd, sbuf);
163 #else
164   return fstat(fd, sbuf);
165 #endif
166 }
167
168 /*******************************************************************
169  An lstat() wrapper that will deal with 64 bit filesizes.
170 ********************************************************************/
171
172 int sys_lstat(char *fname,SMB_STRUCT_STAT *sbuf)
173 {
174 #if defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
175   return lstat64(fname, sbuf);
176 #else
177   return lstat(fname, sbuf);
178 #endif
179 }
180
181 /*******************************************************************
182  An ftruncate() wrapper that will deal with 64 bit filesizes.
183 ********************************************************************/
184
185 int sys_ftruncate(int fd, SMB_OFF_T offset)
186 {
187 #if defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
188   return ftruncate64(fd, offset);
189 #else
190   return ftruncate(fd, offset);
191 #endif
192 }
193
194 /*******************************************************************
195  An lseek() wrapper that will deal with 64 bit filesizes.
196 ********************************************************************/
197
198 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
199 {
200 #if defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
201   return lseek64(fd, offset, whence);
202 #else
203   return lseek(fd, offset, whence);
204 #endif
205 }
206
207 /*******************************************************************
208  An fseek() wrapper that will deal with 64 bit filesizes.
209 ********************************************************************/
210
211 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
212 {
213 #if defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
214   return fseek64(fp, offset, whence);
215 #else
216   return fseek(fp, offset, whence);
217 #endif
218 }
219
220 /*******************************************************************
221  An ftell() wrapper that will deal with 64 bit filesizes.
222 ********************************************************************/
223
224 SMB_OFF_T sys_ftell(FILE *fp)
225 {
226 #if defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
227   return (SMB_OFF_T)ftell64(fp);
228 #else
229   return (SMB_OFF_T)ftell(fp);
230 #endif
231 }
232
233 /*******************************************************************
234 just a unlink wrapper that calls dos_to_unix.
235 ********************************************************************/
236 int dos_unlink(char *fname)
237 {
238   return(unlink(dos_to_unix(fname,False)));
239 }
240
241
242 /*******************************************************************
243 a simple open() wrapper that calls dos_to_unix.
244 ********************************************************************/
245 int dos_open(char *fname,int flags,mode_t mode)
246 {
247   return(open(dos_to_unix(fname,False),flags,mode));
248 }
249
250
251 /*******************************************************************
252 a simple opendir() wrapper that calls dos_to_unix
253 ********************************************************************/
254 DIR *dos_opendir(char *dname)
255 {
256         return(opendir(dos_to_unix(dname,False)));
257 }
258
259 /*******************************************************************
260 and a stat() wrapper that calls dos_to_unix.
261 ********************************************************************/
262 int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf)
263 {
264   return(sys_stat(dos_to_unix(fname,False),sbuf));
265 }
266
267 /*******************************************************************
268 The wait() calls vary between systems
269 ********************************************************************/
270 int sys_waitpid(pid_t pid,int *status,int options)
271 {
272 #ifdef HAVE_WAITPID
273   return waitpid(pid,status,options);
274 #else /* HAVE_WAITPID */
275   return wait4(pid, status, options, NULL);
276 #endif /* HAVE_WAITPID */
277 }
278
279 /*******************************************************************
280 don't forget lstat() that calls dos_to_unix.
281 ********************************************************************/
282 int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf)
283 {
284   return(sys_lstat(dos_to_unix(fname,False),sbuf));
285 }
286
287 /*******************************************************************
288 mkdir() gets a wrapper that calls dos_to_unix.
289 ********************************************************************/
290 int dos_mkdir(char *dname,mode_t mode)
291 {
292   return(mkdir(dos_to_unix(dname,False),mode));
293 }
294
295 /*******************************************************************
296 do does rmdir() - call dos_to_unix
297 ********************************************************************/
298 int dos_rmdir(char *dname)
299 {
300   return(rmdir(dos_to_unix(dname,False)));
301 }
302
303 /*******************************************************************
304 I almost forgot chdir() - call dos_to_unix.
305 ********************************************************************/
306 int dos_chdir(char *dname)
307 {
308   return(chdir(dos_to_unix(dname,False)));
309 }
310
311 /*******************************************************************
312 now for utime() - call dos_to_unix.
313 ********************************************************************/
314 int dos_utime(char *fname,struct utimbuf *times)
315 {
316   /* if the modtime is 0 or -1 then ignore the call and
317      return success */
318   if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
319     return 0;
320   
321   /* if the access time is 0 or -1 then set it to the modtime */
322   if (times->actime == (time_t)0 || times->actime == (time_t)-1)
323     times->actime = times->modtime;
324    
325   return(utime(dos_to_unix(fname,False),times));
326 }
327
328 /*********************************************************
329 for rename across filesystems Patch from Warren Birnbaum 
330 <warrenb@hpcvscdp.cv.hp.com>
331 **********************************************************/
332
333 static int copy_reg(char *source, const char *dest)
334 {
335   SMB_STRUCT_STAT source_stats;
336   int ifd;
337   int ofd;
338   char *buf;
339   int len;                      /* Number of bytes read into `buf'. */
340
341   sys_lstat (source, &source_stats);
342   if (!S_ISREG (source_stats.st_mode))
343     return 1;
344
345   if (unlink (dest) && errno != ENOENT)
346     return 1;
347
348   if((ifd = open (source, O_RDONLY, 0)) < 0)
349     return 1;
350
351   if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
352   {
353     close (ifd);
354     return 1;
355   }
356
357   if((buf = malloc( COPYBUF_SIZE )) == NULL)
358   {
359     close (ifd);  
360     close (ofd);  
361     unlink (dest);
362     return 1;
363   }
364
365   while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
366   {
367     if (write_data(ofd, buf, len) < 0)
368     {
369       close (ifd);
370       close (ofd);
371       unlink (dest);
372       free(buf);
373       return 1;
374     }
375   }
376   free(buf);
377   if (len < 0)
378   {
379     close (ifd);
380     close (ofd);
381     unlink (dest);
382     return 1;
383   }
384
385   if (close (ifd) < 0)
386   {
387     close (ofd);
388     return 1;
389   }
390   if (close (ofd) < 0)
391     return 1;
392
393   /* chown turns off set[ug]id bits for non-root,
394      so do the chmod last.  */
395
396   /* Try to copy the old file's modtime and access time.  */
397   {
398     struct utimbuf tv;
399
400     tv.actime = source_stats.st_atime;
401     tv.modtime = source_stats.st_mtime;
402     if (utime (dest, &tv))
403       return 1;
404   }
405
406   /* Try to preserve ownership.  For non-root it might fail, but that's ok.
407      But root probably wants to know, e.g. if NFS disallows it.  */
408   if (chown (dest, source_stats.st_uid, source_stats.st_gid)
409       && (errno != EPERM))
410     return 1;
411
412   if (chmod (dest, source_stats.st_mode & 07777))
413     return 1;
414
415   unlink (source);
416   return 0;
417 }
418
419 /*******************************************************************
420 for rename() - call dos_to_unix.
421 ********************************************************************/
422 int dos_rename(char *from, char *to)
423 {
424     int rcode;  
425     pstring zfrom, zto;
426
427     pstrcpy (zfrom, dos_to_unix (from, False));
428     pstrcpy (zto, dos_to_unix (to, False));
429     rcode = rename (zfrom, zto);
430
431     if (errno == EXDEV) 
432     {
433       /* Rename across filesystems needed. */
434       rcode = copy_reg (zfrom, zto);        
435     }
436     return rcode;
437 }
438
439 /*******************************************************************
440 for chmod - call dos_to_unix.
441 ********************************************************************/
442 int dos_chmod(char *fname,mode_t mode)
443 {
444   return(chmod(dos_to_unix(fname,False),mode));
445 }
446
447 /*******************************************************************
448 for getwd - takes a UNIX directory name and returns the name
449 in dos format.
450 ********************************************************************/
451 char *dos_getwd(char *s)
452 {
453         char *wd;
454 #ifdef HAVE_GETCWD
455         wd = (char *)getcwd(s, sizeof (pstring));
456 #else
457         wd = (char *)getwd(s);
458 #endif
459         if (wd)
460                 unix_to_dos(wd, True);
461         return wd;
462 }
463
464 /*******************************************************************
465 chown isn't used much but OS/2 doesn't have it
466 ********************************************************************/
467 int sys_chown(char *fname,int uid,int gid)
468 {
469 #ifndef HAVE_CHOWN
470         static int done;
471         if (!done) {
472                 DEBUG(1,("WARNING: no chown!\n"));
473                 done=1;
474         }
475 #else
476         return(chown(fname,uid,gid));
477 #endif
478 }
479
480 /*******************************************************************
481 os/2 also doesn't have chroot
482 ********************************************************************/
483 int sys_chroot(char *dname)
484 {
485 #ifndef HAVE_CHROOT
486         static int done;
487         if (!done) {
488                 DEBUG(1,("WARNING: no chroot!\n"));
489                 done=1;
490         }
491 #else
492         return(chroot(dname));
493 #endif
494 }
495
496 /**************************************************************************
497 A wrapper for gethostbyname() that tries avoids looking up hostnames 
498 in the root domain, which can cause dial-on-demand links to come up for no
499 apparent reason.
500 ****************************************************************************/
501 struct hostent *sys_gethostbyname(char *name)
502 {
503 #ifdef REDUCE_ROOT_DNS_LOOKUPS
504   char query[256], hostname[256];
505   char *domain;
506
507   /* Does this name have any dots in it? If so, make no change */
508
509   if (strchr(name, '.'))
510     return(gethostbyname(name));
511
512   /* Get my hostname, which should have domain name 
513      attached. If not, just do the gethostname on the
514      original string. 
515   */
516
517   gethostname(hostname, sizeof(hostname) - 1);
518   hostname[sizeof(hostname) - 1] = 0;
519   if ((domain = strchr(hostname, '.')) == NULL)
520     return(gethostbyname(name));
521
522   /* Attach domain name to query and do modified query.
523      If names too large, just do gethostname on the
524      original string.
525   */
526
527   if((strlen(name) + strlen(domain)) >= sizeof(query))
528     return(gethostbyname(name));
529
530   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
531   return(gethostbyname(query));
532 #else /* REDUCE_ROOT_DNS_LOOKUPS */
533   return(gethostbyname(name));
534 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
535 }