- added SMBntrename test suite
[ira/wip.git] / source4 / 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         union smb_rename parms;
141
142         parms.generic.level = RAW_RENAME_RENAME;
143         parms.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
144         parms.rename.in.pattern1 = fname_src;
145         parms.rename.in.pattern2 = fname_dst;
146         return NT_STATUS_IS_OK(smb_raw_rename(cli->tree, &parms));
147 }
148
149
150 /****************************************************************************
151  Delete a file.
152 ****************************************************************************/
153 BOOL cli_unlink(struct cli_state *cli, const char *fname)
154 {
155         struct smb_unlink parms;
156
157         parms.in.pattern = fname;
158         if (strchr(fname, '*')) {
159                 parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
160         } else {
161                 parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
162         }
163         return NT_STATUS_IS_OK(smb_raw_unlink(cli->tree, &parms));
164 }
165
166 /****************************************************************************
167  Create a directory.
168 ****************************************************************************/
169 BOOL cli_mkdir(struct cli_state *cli, const char *dname)
170 {
171         union smb_mkdir parms;
172
173         parms.mkdir.level = RAW_MKDIR_MKDIR;
174         parms.mkdir.in.path = dname;
175
176         return NT_STATUS_IS_OK(smb_raw_mkdir(cli->tree, &parms));
177 }
178
179
180 /****************************************************************************
181  Remove a directory.
182 ****************************************************************************/
183 BOOL cli_rmdir(struct cli_state *cli, const char *dname)
184 {
185         struct smb_rmdir parms;
186
187         parms.in.path = dname;
188         return NT_STATUS_IS_OK(smb_raw_rmdir(cli->tree, &parms));
189 }
190
191
192 /****************************************************************************
193  Set or clear the delete on close flag.
194 ****************************************************************************/
195 BOOL cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
196 {
197         union smb_setfileinfo parms;
198         NTSTATUS status;
199
200         parms.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
201         parms.disposition_info.file.fnum = fnum;
202         parms.disposition_info.in.delete_on_close = flag;
203         
204         status = smb_raw_setfileinfo(cli->tree, &parms);
205
206         return NT_STATUS_IS_OK(status);
207 }
208
209
210 /****************************************************************************
211  Create/open a file - exposing the full horror of the NT API :-).
212  Used in CIFS-on-CIFS NTVFS.
213 ****************************************************************************/
214 int cli_nt_create_full(struct cli_state *cli, const char *fname,
215                  uint32 CreatFlags, uint32 DesiredAccess,
216                  uint32 FileAttributes, uint32 ShareAccess,
217                  uint32 CreateDisposition, uint32 CreateOptions,
218                  uint8 SecurityFlags)
219 {
220         union smb_open open_parms;
221         TALLOC_CTX *mem_ctx;
222         NTSTATUS status;
223
224         mem_ctx = talloc_init("raw_open");
225         if (!mem_ctx) return -1;
226
227         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
228         open_parms.ntcreatex.in.flags = CreatFlags;
229         open_parms.ntcreatex.in.root_fid = 0;
230         open_parms.ntcreatex.in.access_mask = DesiredAccess;
231         open_parms.ntcreatex.in.file_attr = FileAttributes;
232         open_parms.ntcreatex.in.alloc_size = 0;
233         open_parms.ntcreatex.in.share_access = ShareAccess;
234         open_parms.ntcreatex.in.open_disposition = CreateDisposition;
235         open_parms.ntcreatex.in.create_options = CreateOptions;
236         open_parms.ntcreatex.in.impersonation = 0;
237         open_parms.ntcreatex.in.security_flags = SecurityFlags;
238         open_parms.ntcreatex.in.fname = fname;
239
240         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
241         talloc_destroy(mem_ctx);
242
243         if (NT_STATUS_IS_OK(status)) {
244                 return open_parms.ntcreatex.out.fnum;
245         }
246         
247         return -1;
248 }
249
250
251 /****************************************************************************
252  Open a file (using SMBopenx)
253  WARNING: if you open with O_WRONLY then getattrE won't work!
254 ****************************************************************************/
255 int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
256 {
257         union smb_open open_parms;
258         unsigned openfn=0;
259         unsigned accessmode=0;
260         TALLOC_CTX *mem_ctx;
261         NTSTATUS status;
262
263         mem_ctx = talloc_init("raw_open");
264         if (!mem_ctx) return -1;
265
266         if (flags & O_CREAT) {
267                 openfn |= OPENX_OPEN_FUNC_CREATE;
268         }
269         if (!(flags & O_EXCL)) {
270                 if (flags & O_TRUNC) {
271                         openfn |= OPENX_OPEN_FUNC_TRUNC;
272                 } else {
273                         openfn |= OPENX_OPEN_FUNC_OPEN;
274                 }
275         }
276
277         accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
278
279         if ((flags & O_ACCMODE) == O_RDWR) {
280                 accessmode |= OPENX_MODE_ACCESS_RDWR;
281         } else if ((flags & O_ACCMODE) == O_WRONLY) {
282                 accessmode |= OPENX_MODE_ACCESS_WRITE;
283         } 
284
285 #if defined(O_SYNC)
286         if ((flags & O_SYNC) == O_SYNC) {
287                 accessmode |= OPENX_MODE_WRITE_THRU;
288         }
289 #endif
290
291         if (share_mode == DENY_FCB) {
292                 accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
293         }
294
295         open_parms.openx.level = RAW_OPEN_OPENX;
296         open_parms.openx.in.flags = 0;
297         open_parms.openx.in.open_mode = accessmode;
298         open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
299         open_parms.openx.in.file_attrs = 0;
300         open_parms.openx.in.write_time = 0;
301         open_parms.openx.in.open_func = openfn;
302         open_parms.openx.in.size = 0;
303         open_parms.openx.in.timeout = 0;
304         open_parms.openx.in.fname = fname;
305
306         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
307         talloc_destroy(mem_ctx);
308
309         if (NT_STATUS_IS_OK(status)) {
310                 return open_parms.openx.out.fnum;
311         }
312
313         return -1;
314 }
315
316
317 /****************************************************************************
318  Close a file.
319 ****************************************************************************/
320 BOOL cli_close(struct cli_state *cli, int fnum)
321 {
322         union smb_close close_parms;
323         NTSTATUS status;
324
325         close_parms.close.level = RAW_CLOSE_CLOSE;
326         close_parms.close.in.fnum = fnum;
327         close_parms.close.in.write_time = 0;
328         status = smb_raw_close(cli->tree, &close_parms);
329         return NT_STATUS_IS_OK(status);
330 }
331
332 /****************************************************************************
333  send a lock with a specified locktype 
334  this is used for testing LOCKING_ANDX_CANCEL_LOCK
335 ****************************************************************************/
336 NTSTATUS cli_locktype(struct cli_state *cli, int fnum, 
337                       uint32 offset, uint32 len, int timeout, unsigned char locktype)
338 {
339         union smb_lock parms;
340         struct smb_lock_entry lock[1];
341         NTSTATUS status;
342
343         parms.lockx.level = RAW_LOCK_LOCKX;
344         parms.lockx.in.fnum = fnum;
345         parms.lockx.in.mode = locktype;
346         parms.lockx.in.timeout = timeout;
347         parms.lockx.in.ulock_cnt = 0;
348         parms.lockx.in.lock_cnt = 1;
349         lock[0].pid = cli->session->pid;
350         lock[0].offset = offset;
351         lock[0].count = len;
352         parms.lockx.in.locks = &lock[0];
353
354         status = smb_raw_lock(cli->tree, &parms);
355         
356         return status;
357 }
358
359
360 /****************************************************************************
361  Lock a file.
362 ****************************************************************************/
363 BOOL cli_lock(struct cli_state *cli, int fnum, 
364               uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
365 {
366         union smb_lock parms;
367         struct smb_lock_entry lock[1];
368         NTSTATUS status;
369
370         parms.lockx.level = RAW_LOCK_LOCKX;
371         parms.lockx.in.fnum = fnum;
372         parms.lockx.in.mode = (lock_type == READ_LOCK? 1 : 0);
373         parms.lockx.in.timeout = timeout;
374         parms.lockx.in.ulock_cnt = 0;
375         parms.lockx.in.lock_cnt = 1;
376         lock[0].pid = cli->session->pid;
377         lock[0].offset = offset;
378         lock[0].count = len;
379         parms.lockx.in.locks = &lock[0];
380
381         status = smb_raw_lock(cli->tree, &parms);
382
383         return NT_STATUS_IS_OK(status);
384 }
385
386
387 /****************************************************************************
388  Unlock a file.
389 ****************************************************************************/
390 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
391 {
392         union smb_lock parms;
393         struct smb_lock_entry lock[1];
394         NTSTATUS status;
395
396         parms.lockx.level = RAW_LOCK_LOCKX;
397         parms.lockx.in.fnum = fnum;
398         parms.lockx.in.mode = 0;
399         parms.lockx.in.timeout = 0;
400         parms.lockx.in.ulock_cnt = 1;
401         parms.lockx.in.lock_cnt = 0;
402         lock[0].pid = cli->session->pid;
403         lock[0].offset = offset;
404         lock[0].count = len;
405         parms.lockx.in.locks = &lock[0];
406         
407         status = smb_raw_lock(cli->tree, &parms);
408         return NT_STATUS_IS_OK(status);
409 }
410         
411
412 /****************************************************************************
413  Lock a file with 64 bit offsets.
414 ****************************************************************************/
415 BOOL cli_lock64(struct cli_state *cli, int fnum, 
416                 SMB_OFF_T offset, SMB_OFF_T len, int timeout, enum brl_type lock_type)
417 {
418         union smb_lock parms;
419         int ltype;
420         struct smb_lock_entry lock[1];
421         NTSTATUS status;
422
423         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
424                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
425         }
426
427         parms.lockx.level = RAW_LOCK_LOCKX;
428         parms.lockx.in.fnum = fnum;
429         
430         ltype = (lock_type == READ_LOCK? 1 : 0);
431         ltype |= LOCKING_ANDX_LARGE_FILES;
432         parms.lockx.in.mode = ltype;
433         parms.lockx.in.timeout = timeout;
434         parms.lockx.in.ulock_cnt = 0;
435         parms.lockx.in.lock_cnt = 1;
436         lock[0].pid = cli->session->pid;
437         lock[0].offset = offset;
438         lock[0].count = len;
439         parms.lockx.in.locks = &lock[0];
440
441         status = smb_raw_lock(cli->tree, &parms);
442         
443         return NT_STATUS_IS_OK(status);
444 }
445
446
447 /****************************************************************************
448  Unlock a file with 64 bit offsets.
449 ****************************************************************************/
450 BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_OFF_T offset, SMB_OFF_T len)
451 {
452         union smb_lock parms;
453         struct smb_lock_entry lock[1];
454         NTSTATUS status;
455
456         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
457                 return cli_unlock(cli, fnum, offset, len);
458         }
459
460         parms.lockx.level = RAW_LOCK_LOCKX;
461         parms.lockx.in.fnum = fnum;
462         parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
463         parms.lockx.in.timeout = 0;
464         parms.lockx.in.ulock_cnt = 1;
465         parms.lockx.in.lock_cnt = 0;
466         lock[0].pid = cli->session->pid;
467         lock[0].offset = offset;
468         lock[0].count = len;
469         parms.lockx.in.locks = &lock[0];
470
471         status = smb_raw_lock(cli->tree, &parms);
472
473         return NT_STATUS_IS_OK(status);
474 }
475
476
477 /****************************************************************************
478  Do a SMBgetattrE call.
479 ****************************************************************************/
480 BOOL cli_getattrE(struct cli_state *cli, int fd,
481                 uint16 *attr, size_t *size,
482                 time_t *c_time, time_t *a_time, time_t *m_time)
483 {               
484         union smb_fileinfo parms;
485         NTSTATUS status;
486
487         parms.getattre.level = RAW_FILEINFO_GETATTRE;
488         parms.getattre.in.fnum = fd;
489
490         status = smb_raw_fileinfo(cli->tree, NULL, &parms);
491
492         if (!NT_STATUS_IS_OK(status))
493                 return False;
494
495         if (size) {
496                 *size = parms.getattre.out.size;
497         }
498
499         if (attr) {
500                 *attr = parms.getattre.out.attrib;
501         }
502
503         if (c_time) {
504                 *c_time = parms.getattre.out.create_time;
505         }
506
507         if (a_time) {
508                 *a_time = &parms.getattre.out.access_time;
509         }
510
511         if (m_time) {
512                 *m_time = &parms.getattre.out.write_time;
513         }
514
515         return True;
516 }
517
518 /****************************************************************************
519  Do a SMBgetatr call
520 ****************************************************************************/
521 BOOL cli_getatr(struct cli_state *cli, const char *fname, 
522                 uint16 *attr, size_t *size, time_t *t)
523 {
524         union smb_fileinfo parms;
525         NTSTATUS status;
526
527         parms.getattr.level = RAW_FILEINFO_GETATTR;
528         parms.getattr.in.fname = fname;
529
530         status = smb_raw_pathinfo(cli->tree, NULL, &parms);
531         
532         if (!NT_STATUS_IS_OK(status)) {
533                 return False;
534         }
535
536         if (size) {
537                 *size = parms.getattr.out.size;
538         }
539
540         if (t) {
541                 *t = parms.getattr.out.write_time;
542         }
543
544         if (attr) {
545                 *attr = parms.getattr.out.attrib;
546         }
547
548         return True;
549 }
550
551
552 /****************************************************************************
553  Do a SMBsetatr call.
554 ****************************************************************************/
555 BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 mode, time_t t)
556 {
557         union smb_setfileinfo parms;
558         NTSTATUS status;
559
560         parms.setattr.level = RAW_SFILEINFO_SETATTR;
561         parms.setattr.in.attrib = mode;
562         parms.setattr.in.write_time = t;
563         parms.setattr.file.fname = fname;
564         
565         status = smb_raw_setpathinfo(cli->tree, &parms);
566
567         return NT_STATUS_IS_OK(status);
568 }
569
570
571 /****************************************************************************
572  Check for existence of a dir.
573 ****************************************************************************/
574 BOOL cli_chkpath(struct cli_state *cli, const char *path)
575 {
576         struct smb_chkpath parms;
577         char *path2;
578         NTSTATUS status;
579
580         path2 = strdup(path);
581         trim_string(path2,NULL,"\\");
582         if (!*path2) {
583                 free(path2);
584                 path2 = strdup("\\");
585         }
586
587         parms.in.path = path2;
588         
589         status = smb_raw_chkpath(cli->tree, &parms);
590
591         free(path2);
592
593         return NT_STATUS_IS_OK(status);
594 }
595
596
597 /****************************************************************************
598  Query disk space.
599 ****************************************************************************/
600 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
601 {
602         union smb_fsinfo fsinfo_parms;
603         TALLOC_CTX *mem_ctx;
604         NTSTATUS status;
605
606         mem_ctx = talloc_init("cli_dskattr");
607
608         fsinfo_parms.dskattr.level = RAW_QFS_DSKATTR;
609         status = smb_raw_fsinfo(cli->tree, mem_ctx, &fsinfo_parms);
610         if (NT_STATUS_IS_OK(status)) {
611                 *bsize = fsinfo_parms.dskattr.out.block_size;
612                 *total = fsinfo_parms.dskattr.out.units_total;
613                 *avail = fsinfo_parms.dskattr.out.units_free;
614         }
615
616         talloc_destroy(mem_ctx);
617         
618         return NT_STATUS_IS_OK(status);
619 }
620
621
622 /****************************************************************************
623  Create and open a temporary file.
624 ****************************************************************************/
625 int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
626 {
627         union smb_open open_parms;
628         TALLOC_CTX *mem_ctx;
629         NTSTATUS status;
630
631         mem_ctx = talloc_init("raw_open");
632         if (!mem_ctx) return -1;
633
634         open_parms.openx.level = RAW_OPEN_CTEMP;
635         open_parms.ctemp.in.attrib = 0;
636         open_parms.ctemp.in.directory = path;
637
638         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
639         if (tmp_path) {
640                 *tmp_path = strdup(open_parms.ctemp.out.name);
641         }
642         talloc_destroy(mem_ctx);
643         if (NT_STATUS_IS_OK(status)) {
644                 return open_parms.ctemp.out.fnum;
645         }
646         return -1;
647 }
648