first public release of samba4 code
[jelmer/samba4-debian.git] / source / libcli / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2002
6    Copyright (C) James Myers 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /****************************************************************************
26  Hard/Symlink a file (UNIX extensions).
27 ****************************************************************************/
28
29 static BOOL cli_link_internal(struct cli_state *cli, 
30                               const char *fname_src, 
31                               const char *fname_dst, BOOL hard_link)
32 {
33         union smb_setfileinfo parms;
34         NTSTATUS status;
35
36         if (hard_link) {
37                 parms.generic.level = SMB_SFILEINFO_UNIX_HLINK;
38                 parms.unix_hlink.file.fname = fname_src;
39                 parms.unix_hlink.in.link_dest = fname_dst;
40         } else {
41                 parms.generic.level = SMB_SFILEINFO_UNIX_LINK;
42                 parms.unix_link.file.fname = fname_src;
43                 parms.unix_link.in.link_dest = fname_dst;
44         }
45         
46         status = smb_raw_setpathinfo(cli->tree, &parms);
47
48         return NT_STATUS_IS_OK(status);
49 }
50
51 /****************************************************************************
52  Map standard UNIX permissions onto wire representations.
53 ****************************************************************************/
54 static uint32  unix_perms_to_wire(mode_t perms)
55 {
56         unsigned int ret = 0;
57
58         ret |= ((perms & S_IXOTH) ?  UNIX_X_OTH : 0);
59         ret |= ((perms & S_IWOTH) ?  UNIX_W_OTH : 0);
60         ret |= ((perms & S_IROTH) ?  UNIX_R_OTH : 0);
61         ret |= ((perms & S_IXGRP) ?  UNIX_X_GRP : 0);
62         ret |= ((perms & S_IWGRP) ?  UNIX_W_GRP : 0);
63         ret |= ((perms & S_IRGRP) ?  UNIX_R_GRP : 0);
64         ret |= ((perms & S_IXUSR) ?  UNIX_X_USR : 0);
65         ret |= ((perms & S_IWUSR) ?  UNIX_W_USR : 0);
66         ret |= ((perms & S_IRUSR) ?  UNIX_R_USR : 0);
67 #ifdef S_ISVTX
68         ret |= ((perms & S_ISVTX) ?  UNIX_STICKY : 0);
69 #endif
70 #ifdef S_ISGID
71         ret |= ((perms & S_ISGID) ?  UNIX_SET_GID : 0);
72 #endif
73 #ifdef S_ISUID
74         ret |= ((perms & S_ISUID) ?  UNIX_SET_UID : 0);
75 #endif
76         return ret;
77 }
78
79 /****************************************************************************
80  Symlink a file (UNIX extensions).
81 ****************************************************************************/
82 BOOL cli_unix_symlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
83 {
84         return cli_link_internal(cli, fname_src, fname_dst, False);
85 }
86
87 /****************************************************************************
88  Hard a file (UNIX extensions).
89 ****************************************************************************/
90 BOOL cli_unix_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
91 {
92         return cli_link_internal(cli, fname_src, fname_dst, True);
93 }
94
95
96 /****************************************************************************
97  Chmod or chown a file internal (UNIX extensions).
98 ****************************************************************************/
99 static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, 
100                                           uint32 mode, uint32 uid, uint32 gid)
101 {
102         union smb_setfileinfo parms;
103         NTSTATUS status;
104
105         parms.generic.level = SMB_SFILEINFO_UNIX_BASIC;
106         parms.unix_basic.file.fname = fname;
107         parms.unix_basic.in.uid = uid;
108         parms.unix_basic.in.gid = gid;
109         parms.unix_basic.in.mode = mode;
110         
111         status = smb_raw_setpathinfo(cli->tree, &parms);
112
113         return NT_STATUS_IS_OK(status);
114 }
115
116 /****************************************************************************
117  chmod a file (UNIX extensions).
118 ****************************************************************************/
119
120 BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
121 {
122         return cli_unix_chmod_chown_internal(cli, fname, 
123                 unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
124 }
125
126 /****************************************************************************
127  chown a file (UNIX extensions).
128 ****************************************************************************/
129 BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
130 {
131         return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
132 }
133
134
135 /****************************************************************************
136  Rename a file.
137 ****************************************************************************/
138 BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
139 {
140         struct smb_rename parms;
141
142         parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
143         parms.in.pattern1 = fname_src;
144         parms.in.pattern2 = fname_dst;
145         return NT_STATUS_IS_OK(smb_raw_rename(cli->tree, &parms));
146 }
147
148
149 /****************************************************************************
150  Delete a file.
151 ****************************************************************************/
152 BOOL cli_unlink(struct cli_state *cli, const char *fname)
153 {
154         struct smb_unlink parms;
155
156         parms.in.pattern = fname;
157         if (strchr(fname, '*')) {
158                 parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
159         } else {
160                 parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
161         }
162         return NT_STATUS_IS_OK(smb_raw_unlink(cli->tree, &parms));
163 }
164
165 /****************************************************************************
166  Create a directory.
167 ****************************************************************************/
168 BOOL cli_mkdir(struct cli_state *cli, const char *dname)
169 {
170         union smb_mkdir parms;
171
172         parms.mkdir.level = RAW_MKDIR_MKDIR;
173         parms.mkdir.in.path = dname;
174
175         return NT_STATUS_IS_OK(smb_raw_mkdir(cli->tree, &parms));
176 }
177
178
179 /****************************************************************************
180  Remove a directory.
181 ****************************************************************************/
182 BOOL cli_rmdir(struct cli_state *cli, const char *dname)
183 {
184         struct smb_rmdir parms;
185
186         parms.in.path = dname;
187         return NT_STATUS_IS_OK(smb_raw_rmdir(cli->tree, &parms));
188 }
189
190
191 /****************************************************************************
192  Set or clear the delete on close flag.
193 ****************************************************************************/
194 BOOL cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
195 {
196         union smb_setfileinfo parms;
197         NTSTATUS status;
198
199         parms.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
200         parms.disposition_info.file.fnum = fnum;
201         parms.disposition_info.in.delete_on_close = flag;
202         
203         status = smb_raw_setfileinfo(cli->tree, &parms);
204
205         return NT_STATUS_IS_OK(status);
206 }
207
208
209 /****************************************************************************
210  Create/open a file - exposing the full horror of the NT API :-).
211  Used in CIFS-on-CIFS NTVFS.
212 ****************************************************************************/
213 int cli_nt_create_full(struct cli_state *cli, const char *fname,
214                  uint32 CreatFlags, uint32 DesiredAccess,
215                  uint32 FileAttributes, uint32 ShareAccess,
216                  uint32 CreateDisposition, uint32 CreateOptions,
217                  uint8 SecurityFlags)
218 {
219         union smb_open open_parms;
220         TALLOC_CTX *mem_ctx;
221         NTSTATUS status;
222
223         mem_ctx = talloc_init("raw_open");
224         if (!mem_ctx) return -1;
225
226         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
227         open_parms.ntcreatex.in.flags = CreatFlags;
228         open_parms.ntcreatex.in.root_fid = 0;
229         open_parms.ntcreatex.in.access_mask = DesiredAccess;
230         open_parms.ntcreatex.in.file_attr = FileAttributes;
231         open_parms.ntcreatex.in.alloc_size = 0;
232         open_parms.ntcreatex.in.share_access = ShareAccess;
233         open_parms.ntcreatex.in.open_disposition = CreateDisposition;
234         open_parms.ntcreatex.in.create_options = CreateOptions;
235         open_parms.ntcreatex.in.impersonation = 0;
236         open_parms.ntcreatex.in.security_flags = SecurityFlags;
237         open_parms.ntcreatex.in.fname = fname;
238
239         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
240         talloc_destroy(mem_ctx);
241
242         if (NT_STATUS_IS_OK(status)) {
243                 return open_parms.ntcreatex.out.fnum;
244         }
245         
246         return -1;
247 }
248
249
250 /****************************************************************************
251  Open a file (using SMBopenx)
252  WARNING: if you open with O_WRONLY then getattrE won't work!
253 ****************************************************************************/
254 int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
255 {
256         union smb_open open_parms;
257         unsigned openfn=0;
258         unsigned accessmode=0;
259         TALLOC_CTX *mem_ctx;
260         NTSTATUS status;
261
262         mem_ctx = talloc_init("raw_open");
263         if (!mem_ctx) return -1;
264
265         if (flags & O_CREAT) {
266                 openfn |= OPENX_OPEN_FUNC_CREATE;
267         }
268         if (!(flags & O_EXCL)) {
269                 if (flags & O_TRUNC) {
270                         openfn |= OPENX_OPEN_FUNC_TRUNC;
271                 } else {
272                         openfn |= OPENX_OPEN_FUNC_OPEN;
273                 }
274         }
275
276         accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
277
278         if ((flags & O_ACCMODE) == O_RDWR) {
279                 accessmode |= OPENX_MODE_ACCESS_RDWR;
280         } else if ((flags & O_ACCMODE) == O_WRONLY) {
281                 accessmode |= OPENX_MODE_ACCESS_WRITE;
282         } 
283
284 #if defined(O_SYNC)
285         if ((flags & O_SYNC) == O_SYNC) {
286                 accessmode |= OPENX_MODE_WRITE_THRU;
287         }
288 #endif
289
290         if (share_mode == DENY_FCB) {
291                 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
292         }
293
294         open_parms.openx.level = RAW_OPEN_OPENX;
295         open_parms.openx.in.flags = 0;
296         open_parms.openx.in.open_mode = accessmode;
297         open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
298         open_parms.openx.in.file_attrs = 0;
299         open_parms.openx.in.write_time = 0;
300         open_parms.openx.in.open_func = openfn;
301         open_parms.openx.in.size = 0;
302         open_parms.openx.in.timeout = 0;
303         open_parms.openx.in.fname = fname;
304
305         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
306         talloc_destroy(mem_ctx);
307
308         if (NT_STATUS_IS_OK(status)) {
309                 return open_parms.openx.out.fnum;
310         }
311
312         return -1;
313 }
314
315
316 /****************************************************************************
317  Close a file.
318 ****************************************************************************/
319 BOOL cli_close(struct cli_state *cli, int fnum)
320 {
321         union smb_close close_parms;
322         NTSTATUS status;
323
324         close_parms.close.level = RAW_CLOSE_CLOSE;
325         close_parms.close.in.fnum = fnum;
326         close_parms.close.in.write_time = 0;
327         status = smb_raw_close(cli->tree, &close_parms);
328         return NT_STATUS_IS_OK(status);
329 }
330
331 /****************************************************************************
332  send a lock with a specified locktype 
333  this is used for testing LOCKING_ANDX_CANCEL_LOCK
334 ****************************************************************************/
335 NTSTATUS cli_locktype(struct cli_state *cli, int fnum, 
336                       uint32 offset, uint32 len, int timeout, unsigned char locktype)
337 {
338         union smb_lock parms;
339         struct smb_lock_entry lock[1];
340         NTSTATUS status;
341
342         parms.lockx.level = RAW_LOCK_LOCKX;
343         parms.lockx.in.fnum = fnum;
344         parms.lockx.in.mode = locktype;
345         parms.lockx.in.timeout = timeout;
346         parms.lockx.in.ulock_cnt = 0;
347         parms.lockx.in.lock_cnt = 1;
348         lock[0].pid = cli->session->pid;
349         lock[0].offset = offset;
350         lock[0].count = len;
351         parms.lockx.in.locks = &lock[0];
352
353         status = smb_raw_lock(cli->tree, &parms);
354         
355         return status;
356 }
357
358
359 /****************************************************************************
360  Lock a file.
361 ****************************************************************************/
362 BOOL cli_lock(struct cli_state *cli, int fnum, 
363               uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
364 {
365         union smb_lock parms;
366         struct smb_lock_entry lock[1];
367         NTSTATUS status;
368
369         parms.lockx.level = RAW_LOCK_LOCKX;
370         parms.lockx.in.fnum = fnum;
371         parms.lockx.in.mode = (lock_type == READ_LOCK? 1 : 0);
372         parms.lockx.in.timeout = timeout;
373         parms.lockx.in.ulock_cnt = 0;
374         parms.lockx.in.lock_cnt = 1;
375         lock[0].pid = cli->session->pid;
376         lock[0].offset = offset;
377         lock[0].count = len;
378         parms.lockx.in.locks = &lock[0];
379
380         status = smb_raw_lock(cli->tree, &parms);
381
382         return NT_STATUS_IS_OK(status);
383 }
384
385
386 /****************************************************************************
387  Unlock a file.
388 ****************************************************************************/
389 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
390 {
391         union smb_lock parms;
392         struct smb_lock_entry lock[1];
393         NTSTATUS status;
394
395         parms.lockx.level = RAW_LOCK_LOCKX;
396         parms.lockx.in.fnum = fnum;
397         parms.lockx.in.mode = 0;
398         parms.lockx.in.timeout = 0;
399         parms.lockx.in.ulock_cnt = 1;
400         parms.lockx.in.lock_cnt = 0;
401         lock[0].pid = cli->session->pid;
402         lock[0].offset = offset;
403         lock[0].count = len;
404         parms.lockx.in.locks = &lock[0];
405         
406         status = smb_raw_lock(cli->tree, &parms);
407         return NT_STATUS_IS_OK(status);
408 }
409         
410
411 /****************************************************************************
412  Lock a file with 64 bit offsets.
413 ****************************************************************************/
414 BOOL cli_lock64(struct cli_state *cli, int fnum, 
415                 SMB_OFF_T offset, SMB_OFF_T len, int timeout, enum brl_type lock_type)
416 {
417         union smb_lock parms;
418         int ltype;
419         struct smb_lock_entry lock[1];
420         NTSTATUS status;
421
422         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
423                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
424         }
425
426         parms.lockx.level = RAW_LOCK_LOCKX;
427         parms.lockx.in.fnum = fnum;
428         
429         ltype = (lock_type == READ_LOCK? 1 : 0);
430         ltype |= LOCKING_ANDX_LARGE_FILES;
431         parms.lockx.in.mode = ltype;
432         parms.lockx.in.timeout = timeout;
433         parms.lockx.in.ulock_cnt = 0;
434         parms.lockx.in.lock_cnt = 1;
435         lock[0].pid = cli->session->pid;
436         lock[0].offset = offset;
437         lock[0].count = len;
438         parms.lockx.in.locks = &lock[0];
439
440         status = smb_raw_lock(cli->tree, &parms);
441         
442         return NT_STATUS_IS_OK(status);
443 }
444
445
446 /****************************************************************************
447  Unlock a file with 64 bit offsets.
448 ****************************************************************************/
449 BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_OFF_T offset, SMB_OFF_T len)
450 {
451         union smb_lock parms;
452         struct smb_lock_entry lock[1];
453         NTSTATUS status;
454
455         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
456                 return cli_unlock(cli, fnum, offset, len);
457         }
458
459         parms.lockx.level = RAW_LOCK_LOCKX;
460         parms.lockx.in.fnum = fnum;
461         parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
462         parms.lockx.in.timeout = 0;
463         parms.lockx.in.ulock_cnt = 1;
464         parms.lockx.in.lock_cnt = 0;
465         lock[0].pid = cli->session->pid;
466         lock[0].offset = offset;
467         lock[0].count = len;
468         parms.lockx.in.locks = &lock[0];
469
470         status = smb_raw_lock(cli->tree, &parms);
471
472         return NT_STATUS_IS_OK(status);
473 }
474
475
476 /****************************************************************************
477  Do a SMBgetattrE call.
478 ****************************************************************************/
479 BOOL cli_getattrE(struct cli_state *cli, int fd,
480                 uint16 *attr, size_t *size,
481                 time_t *c_time, time_t *a_time, time_t *m_time)
482 {               
483         union smb_fileinfo parms;
484         NTSTATUS status;
485
486         parms.getattre.level = RAW_FILEINFO_GETATTRE;
487         parms.getattre.in.fnum = fd;
488
489         status = smb_raw_fileinfo(cli->tree, NULL, &parms);
490
491         if (!NT_STATUS_IS_OK(status))
492                 return False;
493
494         if (size) {
495                 *size = parms.getattre.out.size;
496         }
497
498         if (attr) {
499                 *attr = parms.getattre.out.attrib;
500         }
501
502         if (c_time) {
503                 *c_time = parms.getattre.out.create_time;
504         }
505
506         if (a_time) {
507                 *a_time = &parms.getattre.out.access_time;
508         }
509
510         if (m_time) {
511                 *m_time = &parms.getattre.out.write_time;
512         }
513
514         return True;
515 }
516
517 /****************************************************************************
518  Do a SMBgetatr call
519 ****************************************************************************/
520 BOOL cli_getatr(struct cli_state *cli, const char *fname, 
521                 uint16 *attr, size_t *size, time_t *t)
522 {
523         union smb_fileinfo parms;
524         NTSTATUS status;
525
526         parms.getattr.level = RAW_FILEINFO_GETATTR;
527         parms.getattr.in.fname = fname;
528
529         status = smb_raw_pathinfo(cli->tree, NULL, &parms);
530         
531         if (!NT_STATUS_IS_OK(status)) {
532                 return False;
533         }
534
535         if (size) {
536                 *size = parms.getattr.out.size;
537         }
538
539         if (t) {
540                 *t = parms.getattr.out.write_time;
541         }
542
543         if (attr) {
544                 *attr = parms.getattr.out.attrib;
545         }
546
547         return True;
548 }
549
550
551 /****************************************************************************
552  Do a SMBsetatr call.
553 ****************************************************************************/
554 BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 mode, time_t t)
555 {
556         union smb_setfileinfo parms;
557         NTSTATUS status;
558
559         parms.setattr.level = RAW_SFILEINFO_SETATTR;
560         parms.setattr.in.attrib = mode;
561         parms.setattr.in.write_time = t;
562         parms.setattr.file.fname = fname;
563         
564         status = smb_raw_setpathinfo(cli->tree, &parms);
565
566         return NT_STATUS_IS_OK(status);
567 }
568
569
570 /****************************************************************************
571  Check for existence of a dir.
572 ****************************************************************************/
573 BOOL cli_chkpath(struct cli_state *cli, const char *path)
574 {
575         struct smb_chkpath parms;
576         char *path2;
577         NTSTATUS status;
578
579         path2 = strdup(path);
580         trim_string(path2,NULL,"\\");
581         if (!*path2) {
582                 free(path2);
583                 path2 = strdup("\\");
584         }
585
586         parms.in.path = path2;
587         
588         status = smb_raw_chkpath(cli->tree, &parms);
589
590         free(path2);
591
592         return NT_STATUS_IS_OK(status);
593 }
594
595
596 /****************************************************************************
597  Query disk space.
598 ****************************************************************************/
599 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
600 {
601         union smb_fsinfo fsinfo_parms;
602         TALLOC_CTX *mem_ctx;
603         NTSTATUS status;
604
605         mem_ctx = talloc_init("cli_dskattr");
606
607         fsinfo_parms.dskattr.level = RAW_QFS_DSKATTR;
608         status = smb_raw_fsinfo(cli->tree, mem_ctx, &fsinfo_parms);
609         if (NT_STATUS_IS_OK(status)) {
610                 *bsize = fsinfo_parms.dskattr.out.block_size;
611                 *total = fsinfo_parms.dskattr.out.units_total;
612                 *avail = fsinfo_parms.dskattr.out.units_free;
613         }
614
615         talloc_destroy(mem_ctx);
616         
617         return NT_STATUS_IS_OK(status);
618 }
619
620
621 /****************************************************************************
622  Create and open a temporary file.
623 ****************************************************************************/
624 int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
625 {
626         union smb_open open_parms;
627         TALLOC_CTX *mem_ctx;
628         NTSTATUS status;
629
630         mem_ctx = talloc_init("raw_open");
631         if (!mem_ctx) return -1;
632
633         open_parms.openx.level = RAW_OPEN_CTEMP;
634         open_parms.ctemp.in.attrib = 0;
635         open_parms.ctemp.in.directory = path;
636
637         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
638         if (tmp_path) {
639                 *tmp_path = strdup(open_parms.ctemp.out.name);
640         }
641         talloc_destroy(mem_ctx);
642         if (NT_STATUS_IS_OK(status)) {
643                 return open_parms.ctemp.out.fnum;
644         }
645         return -1;
646 }
647