first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[jra/samba/.git] / source3 / lib / doscalls.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba system utilities
5    Copyright (C) Jeremy Allison 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 /*
25  * Wrappers for calls that need to translate to
26  * DOS/Windows semantics. Note that the pathnames
27  * in all these functions referred to as 'DOS' names
28  * are actually in UNIX path format (ie. '/' instead of
29  * '\' directory separators etc.), but the codepage they
30  * are in is still the client codepage, hence the 'DOS'
31  * name.
32  */
33
34 extern int DEBUGLEVEL;
35
36 /*******************************************************************
37  Unlink wrapper that calls dos_to_unix.
38 ********************************************************************/
39
40 int dos_unlink(char *fname)
41 {
42   return(unlink(dos_to_unix(fname,False)));
43 }
44
45 /*******************************************************************
46  Open() wrapper that calls dos_to_unix.
47 ********************************************************************/
48
49 int dos_open(char *fname,int flags,mode_t mode)
50 {
51   return(sys_open(dos_to_unix(fname,False),flags,mode));
52 }
53
54 /*******************************************************************
55  Opendir() wrapper that calls dos_to_unix.
56 ********************************************************************/
57
58 DIR *dos_opendir(char *dname)
59 {
60   return(opendir(dos_to_unix(dname,False)));
61 }
62
63 /*******************************************************************
64  Readdirname() wrapper that calls unix_to_dos.
65 ********************************************************************/
66
67 char *dos_readdirname(DIR *p)
68 {
69   char *dname = readdirname(p);
70
71   if (!dname)
72     return(NULL);
73  
74   unix_to_dos(dname, True);
75   return(dname);
76 }
77
78 /*******************************************************************
79  A chown() wrapper that calls dos_to_unix.
80 ********************************************************************/
81
82 int dos_chown(char *fname, uid_t uid, gid_t gid)
83 {
84   return(sys_chown(dos_to_unix(fname,False),uid,gid));
85 }
86
87 /*******************************************************************
88  A stat() wrapper that calls dos_to_unix.
89 ********************************************************************/
90
91 int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf)
92 {
93   return(sys_stat(dos_to_unix(fname,False),sbuf));
94 }
95
96 /*******************************************************************
97  An lstat() that calls dos_to_unix.
98 ********************************************************************/
99
100 int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf)
101 {
102   return(sys_lstat(dos_to_unix(fname,False),sbuf));
103 }
104
105 /*******************************************************************
106  Mkdir() that calls dos_to_unix.
107  Cope with UNIXes that don't allow high order mode bits on mkdir.
108  Patch from gcarter@lanier.com.
109 ********************************************************************/
110
111 int dos_mkdir(char *dname,mode_t mode)
112 {
113   int ret = mkdir(dos_to_unix(dname,False),mode);
114   if(!ret)
115     return(dos_chmod(dname,mode));
116   else
117     return ret;
118 }
119
120 /*******************************************************************
121  Rmdir() - call dos_to_unix.
122 ********************************************************************/
123
124 int dos_rmdir(char *dname)
125 {
126   return(rmdir(dos_to_unix(dname,False)));
127 }
128
129 /*******************************************************************
130  chdir() - call dos_to_unix.
131 ********************************************************************/
132
133 int dos_chdir(char *dname)
134 {
135   return(chdir(dos_to_unix(dname,False)));
136 }
137
138 /*******************************************************************
139  Utime() - call dos_to_unix.
140 ********************************************************************/
141
142 int dos_utime(char *fname,struct utimbuf *times)
143 {
144   /* if the modtime is 0 or -1 then ignore the call and
145      return success */
146   if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
147     return 0;
148   
149   /* if the access time is 0 or -1 then set it to the modtime */
150   if (times->actime == (time_t)0 || times->actime == (time_t)-1)
151     times->actime = times->modtime;
152    
153   return(utime(dos_to_unix(fname,False),times));
154 }
155
156 /*********************************************************
157  For rename across filesystems Patch from Warren Birnbaum 
158  <warrenb@hpcvscdp.cv.hp.com>
159 **********************************************************/
160
161 static int copy_reg(char *source, const char *dest)
162 {
163   SMB_STRUCT_STAT source_stats;
164   int ifd;
165   int ofd;
166   char *buf;
167   int len;                      /* Number of bytes read into `buf'. */
168
169   sys_lstat (source, &source_stats);
170   if (!S_ISREG (source_stats.st_mode))
171     return 1;
172
173   if (unlink (dest) && errno != ENOENT)
174     return 1;
175
176   if((ifd = sys_open (source, O_RDONLY, 0)) < 0)
177     return 1;
178
179   if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
180   {
181     close (ifd);
182     return 1;
183   }
184
185   if((buf = malloc( COPYBUF_SIZE )) == NULL)
186   {
187     close (ifd);  
188     close (ofd);  
189     unlink (dest);
190     return 1;
191   }
192
193   while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
194   {
195     if (write_data(ofd, buf, len) < 0)
196     {
197       close (ifd);
198       close (ofd);
199       unlink (dest);
200       free(buf);
201       return 1;
202     }
203   }
204   free(buf);
205   if (len < 0)
206   {
207     close (ifd);
208     close (ofd);
209     unlink (dest);
210     return 1;
211   }
212
213   if (close (ifd) < 0)
214   {
215     close (ofd);
216     return 1;
217   }
218   if (close (ofd) < 0)
219     return 1;
220
221   /* chown turns off set[ug]id bits for non-root,
222      so do the chmod last.  */
223
224   /* Try to copy the old file's modtime and access time.  */
225   {
226     struct utimbuf tv;
227
228     tv.actime = source_stats.st_atime;
229     tv.modtime = source_stats.st_mtime;
230     if (utime (dest, &tv))
231       return 1;
232   }
233
234   /* Try to preserve ownership.  For non-root it might fail, but that's ok.
235      But root probably wants to know, e.g. if NFS disallows it.  */
236   if (chown (dest, source_stats.st_uid, source_stats.st_gid)
237       && (errno != EPERM))
238     return 1;
239
240   if (chmod (dest, source_stats.st_mode & 07777))
241     return 1;
242
243   unlink (source);
244   return 0;
245 }
246
247 /*******************************************************************
248  Rename() - call dos_to_unix.
249 ********************************************************************/
250
251 int dos_rename(char *from, char *to)
252 {
253     int rcode;  
254     pstring zfrom, zto;
255
256     pstrcpy (zfrom, dos_to_unix (from, False));
257     pstrcpy (zto, dos_to_unix (to, False));
258     rcode = rename (zfrom, zto);
259
260     if (errno == EXDEV) 
261     {
262       /* Rename across filesystems needed. */
263       rcode = copy_reg (zfrom, zto);        
264     }
265     return rcode;
266 }
267
268 /*******************************************************************
269  Chmod - call dos_to_unix.
270 ********************************************************************/
271
272 int dos_chmod(char *fname,mode_t mode)
273 {
274   return(chmod(dos_to_unix(fname,False),mode));
275 }
276
277 /*******************************************************************
278  Getwd - takes a UNIX directory name and returns the name
279  in dos format.
280 ********************************************************************/
281
282 char *dos_getwd(char *unix_path)
283 {
284         char *wd;
285         wd = sys_getwd(unix_path);
286         if (wd)
287                 unix_to_dos(wd, True);
288         return wd;
289 }
290
291 /*******************************************************************
292  Check if a DOS file exists.
293 ********************************************************************/
294
295 BOOL dos_file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
296 {
297   return file_exist(dos_to_unix(fname, False), sbuf);
298 }
299
300 /*******************************************************************
301  Check if a DOS directory exists.
302 ********************************************************************/
303
304 BOOL dos_directory_exist(char *dname,SMB_STRUCT_STAT *st)
305 {
306   return directory_exist(dos_to_unix(dname, False), st);
307 }
308
309 /*******************************************************************
310  Return the modtime of a DOS pathname.
311 ********************************************************************/
312
313 time_t dos_file_modtime(char *fname)
314 {
315   return file_modtime(dos_to_unix(fname, False));
316 }
317
318 /*******************************************************************
319  Return the file size of a DOS pathname.
320 ********************************************************************/
321
322 SMB_OFF_T dos_file_size(char *file_name)
323 {
324   return get_file_size(dos_to_unix(file_name, False));
325 }
326
327 /*******************************************************************
328  A wrapper for dos_chdir().
329 ********************************************************************/
330
331 int dos_ChDir(char *path)
332 {
333   int res;
334   static pstring LastDir="";
335
336   if (strcsequal(path,"."))
337     return(0);
338
339   if (*path == '/' && strcsequal(LastDir,path))
340     return(0);
341
342   DEBUG(3,("dos_ChDir to %s\n",path));
343
344   res = dos_chdir(path);
345   if (!res)
346     pstrcpy(LastDir,path);
347   return(res);
348 }
349
350 /* number of list structures for a caching GetWd function. */
351 #define MAX_GETWDCACHE (50)
352
353 struct
354 {
355   SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
356   SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
357   char *dos_path; /* The pathname in DOS format. */
358   BOOL valid;
359 } ino_list[MAX_GETWDCACHE];
360
361 BOOL use_getwd_cache=True;
362
363 /****************************************************************************
364  Prompte a ptr (to make it recently used)
365 ****************************************************************************/
366
367 static void array_promote(char *array,int elsize,int element)
368 {
369   char *p;
370   if (element == 0)
371     return;
372
373   p = (char *)malloc(elsize);
374
375   if (!p)
376     {
377       DEBUG(5,("Ahh! Can't malloc\n"));
378       return;
379     }
380   memcpy(p,array + element * elsize, elsize);
381   memmove(array + elsize,array,elsize*element);
382   memcpy(array,p,elsize);
383   free(p);
384 }
385
386 /*******************************************************************
387  Return the absolute current directory path - given a UNIX pathname.
388  Note that this path is returned in DOS format, not UNIX
389  format.
390 ********************************************************************/
391
392 char *dos_GetWd(char *path)
393 {
394   pstring s;
395   static BOOL getwd_cache_init = False;
396   SMB_STRUCT_STAT st, st2;
397   int i;
398
399   *s = 0;
400
401   if (!use_getwd_cache)
402     return(dos_getwd(path));
403
404   /* init the cache */
405   if (!getwd_cache_init)
406   {
407     getwd_cache_init = True;
408     for (i=0;i<MAX_GETWDCACHE;i++)
409     {
410       string_init(&ino_list[i].dos_path,"");
411       ino_list[i].valid = False;
412     }
413   }
414
415   /*  Get the inode of the current directory, if this doesn't work we're
416       in trouble :-) */
417
418   if (sys_stat(".",&st) == -1)
419   {
420     DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
421     return(dos_getwd(path));
422   }
423
424
425   for (i=0; i<MAX_GETWDCACHE; i++)
426     if (ino_list[i].valid)
427     {
428
429       /*  If we have found an entry with a matching inode and dev number
430           then find the inode number for the directory in the cached string.
431           If this agrees with that returned by the stat for the current
432           directory then all is o.k. (but make sure it is a directory all
433           the same...) */
434
435       if (st.st_ino == ino_list[i].inode &&
436           st.st_dev == ino_list[i].dev)
437       {
438         if (dos_stat(ino_list[i].dos_path,&st2) == 0)
439         {
440           if (st.st_ino == st2.st_ino &&
441               st.st_dev == st2.st_dev &&
442               (st2.st_mode & S_IFMT) == S_IFDIR)
443           {
444             pstrcpy (path, ino_list[i].dos_path);
445
446             /* promote it for future use */
447             array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
448             return (path);
449           }
450           else
451           {
452             /*  If the inode is different then something's changed,
453                 scrub the entry and start from scratch. */
454             ino_list[i].valid = False;
455           }
456         }
457       }
458     }
459
460
461   /*  We don't have the information to hand so rely on traditional methods.
462       The very slow getcwd, which spawns a process on some systems, or the
463       not quite so bad getwd. */
464
465   if (!dos_getwd(s))
466   {
467     DEBUG(0,("dos_GetWd: dos_getwd call failed, errno %s\n",strerror(errno)));
468     return (NULL);
469   }
470
471   pstrcpy(path,s);
472
473   DEBUG(5,("dos_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
474
475   /* add it to the cache */
476   i = MAX_GETWDCACHE - 1;
477   string_set(&ino_list[i].dos_path,s);
478   ino_list[i].dev = st.st_dev;
479   ino_list[i].inode = st.st_ino;
480   ino_list[i].valid = True;
481
482   /* put it at the top of the list */
483   array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
484
485   return (path);
486 }