2 Unix SMB/CIFS implementation.
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
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 3 of the License, or
10 (at your option) any later version.
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.
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.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
24 1. Restore can now restore files with long file names
25 2. Save now saves directory information so that we can restore
26 directory creation times
27 3. tar now accepts both UNIX path names and DOS path names. I prefer
28 those lovely /'s to those UGLY \'s :-)
29 4. the files to exclude can be specified as a regular expression by adding
30 an r flag to the other tar flags. Eg:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
40 #include "client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct {
51 /* These times are normally kept in GMT */
52 struct timespec mtime_ts;
53 struct timespec atime_ts;
54 struct timespec ctime_ts;
55 char *name; /* This is dynamically allocate */
57 file_info2 *next, *prev; /* Used in the stack ... */
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
74 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
83 /* Incremental mode */
84 static BOOL tar_inc=False;
85 /* Reset archive bit */
86 static BOOL tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static BOOL tar_excl=True;
89 /* use regular expressions for search on file names */
90 static BOOL tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static BOOL dry_run=False;
93 /* Dump files with System attribute */
94 static BOOL tar_system=True;
95 /* Dump files with Hidden attribute */
96 static BOOL tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static BOOL tar_noisy=True;
99 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
102 static char **cliplist=NULL;
104 static BOOL must_free_cliplist = False;
106 extern file_info def_finfo;
107 extern BOOL lowercase;
109 extern BOOL readbraw_supported;
111 extern pstring cur_dir;
112 extern int get_total_time_ms;
113 extern int get_total_size;
115 static int blocksize=20;
116 static int tarhandle;
118 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
119 const char *amode, unsigned char ftype);
120 static void do_atar(char *rname,char *lname,file_info *finfo1);
121 static void do_tar(file_info *finfo);
122 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
123 static void fixtarname(char *tptr, const char *fp, size_t l);
124 static int dotarbuf(int f, char *b, int n);
125 static void dozerobuf(int f, int n);
126 static void dotareof(int f);
127 static void initarbuf(void);
129 /* restore functions */
130 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
131 static long unoct(char *p, int ndgs);
132 static void do_tarput(void);
133 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
136 * tar specific utitlities
139 /*******************************************************************
140 Create a string of size size+1 (for the null)
141 *******************************************************************/
143 static char *string_create_s(int size)
147 tmp = (char *)SMB_MALLOC(size+1);
150 DEBUG(0, ("Out of memory in string_create_s\n"));
156 /****************************************************************************
157 Write a tar header to buffer
158 ****************************************************************************/
160 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
161 const char *amode, unsigned char ftype)
167 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169 memset(hb.dummy, 0, sizeof(hb.dummy));
172 /* We will be prepending a '.' in fixtarheader so use +2 to
173 * take care of the . and terminating zero. JRA.
176 /* write a GNU tar style long header */
178 b = (char *)SMB_MALLOC(l+TBLOCK+100);
180 DEBUG(0,("out of memory\n"));
183 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
184 memset(b, 0, l+TBLOCK+100);
185 fixtarname(b, aname, l+2);
187 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
188 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
192 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
195 strlower_m(hb.dbuf.name);
197 /* write out a "standard" tar format header */
199 hb.dbuf.name[NAMSIZ-1]='\0';
200 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
201 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
202 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
203 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
205 if (size > (SMB_BIG_UINT)077777777777LL) {
207 if (size > (SMB_BIG_UINT)077777777777) {
210 /* This is a non-POSIX compatible extention to store files
213 memset(hb.dbuf.size, 0, 4);
215 for (i = 8, jp=(char*)&size; i; i--)
216 hb.dbuf.size[i+3] = *(jp++);
218 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
219 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
220 memset(hb.dbuf.linkname, 0, NAMSIZ);
221 hb.dbuf.linkflag=ftype;
223 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
226 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
227 hb.dbuf.chksum[6] = '\0';
229 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
232 /****************************************************************************
233 Read a tar header into a hblock structure, and validate
234 ***************************************************************************/
236 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
243 * read in a "standard" tar format header - we're not that interested
244 * in that many fields, though
247 /* check the checksum */
248 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
254 /* compensate for blanks in chksum header */
255 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
258 chk += ' ' * sizeof(hb->dbuf.chksum);
260 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
262 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
263 chk, fchk, hb->dbuf.chksum));
266 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
267 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
271 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
272 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
276 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
278 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
279 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
280 strlen(hb->dbuf.name) + 1, True);
282 /* can't handle some links at present */
283 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
284 if (hb->dbuf.linkflag == 0) {
285 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
288 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
289 /* Do nothing here at the moment. do_tarput will handle this
290 as long as the longlink gets back to it, as it has to advance
291 the buffer pointer, etc */
293 DEBUG(0, ("this tar file appears to contain some kind \
294 of link other than a GNUtar Longlink - ignoring\n"));
300 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
301 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
304 finfo->mode=0; /* we don't care about mode at the moment, we'll
305 * just make it a regular file */
309 * Bug fix by richard@sj.co.uk
311 * REC: restore times correctly (as does tar)
312 * We only get the modification time of the file; set the creation time
313 * from the mod. time, and the access time to current time
315 finfo->mtime_ts = finfo->ctime_ts =
316 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
317 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
318 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
323 /****************************************************************************
324 Write out the tar buffer to tape or wherever
325 ****************************************************************************/
327 static int dotarbuf(int f, char *b, int n)
334 /* This routine and the next one should be the only ones that do write()s */
335 if (tp + n >= tbufsiz) {
339 memcpy(tarbuf + tp, b, diff);
340 fail=fail && (1+write(f, tarbuf, tbufsiz));
345 while (n >= tbufsiz) {
346 fail=fail && (1 + write(f, b, tbufsiz));
353 memcpy(tarbuf+tp, b, n);
357 return(fail ? writ : 0);
360 /****************************************************************************
361 Write zeros to buffer / tape
362 ****************************************************************************/
364 static void dozerobuf(int f, int n)
366 /* short routine just to write out n zeros to buffer -
367 * used to round files to nearest block
368 * and to do tar EOFs */
373 if (n+tp >= tbufsiz) {
374 memset(tarbuf+tp, 0, tbufsiz-tp);
375 write(f, tarbuf, tbufsiz);
376 memset(tarbuf, 0, (tp+=n-tbufsiz));
378 memset(tarbuf+tp, 0, n);
383 /****************************************************************************
385 ****************************************************************************/
387 static void initarbuf(void)
389 /* initialize tar buffer */
390 tbufsiz=blocksize*TBLOCK;
391 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
393 /* reset tar buffer pointer and tar file counter and total dumped */
394 tp=0; ntarf=0; ttarf=0;
397 /****************************************************************************
398 Write two zero blocks at end of file
399 ****************************************************************************/
401 static void dotareof(int f)
403 SMB_STRUCT_STAT stbuf;
404 /* Two zero blocks at end of file, write out full buffer */
409 (void) dozerobuf(f, TBLOCK);
410 (void) dozerobuf(f, TBLOCK);
412 if (sys_fstat(f, &stbuf) == -1) {
413 DEBUG(0, ("Couldn't stat file handle\n"));
417 /* Could be a pipe, in which case S_ISREG should fail,
418 * and we should write out at full size */
420 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
423 /****************************************************************************
424 (Un)mangle DOS pathname, make nonabsolute
425 ****************************************************************************/
427 static void fixtarname(char *tptr, const char *fp, size_t l)
429 /* add a '.' to start of file name, convert from ugly dos \'s in path
430 * to lovely unix /'s :-} */
434 StrnCpy(tptr, fp, l-1);
435 string_replace(tptr, '\\', '/');
438 /****************************************************************************
439 Convert from decimal to octal string
440 ****************************************************************************/
442 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
444 /* Converts long to octal string, pads with leading zeros */
446 /* skip final null, but do final space */
450 /* Loop does at least one digit */
452 p[--ndgs] = '0' + (char) (value & 7);
454 } while (ndgs > 0 && value != 0);
456 /* Do leading zeros */
461 /****************************************************************************
462 Convert from octal string to long
463 ***************************************************************************/
465 static long unoct(char *p, int ndgs)
468 /* Converts octal string to long, ignoring any non-digit */
471 if (isdigit((int)*p))
472 value = (value << 3) | (long) (*p - '0');
480 /****************************************************************************
481 Compare two strings in a slash insensitive way, allowing s1 to match s2
482 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
483 a file in any subdirectory of s1, declare a match.
484 ***************************************************************************/
486 static int strslashcmp(char *s1, char *s2)
490 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
491 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
495 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
498 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
501 /* ignore trailing slash on s1 */
502 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
505 /* check for s1 is an "initial" string of s2 */
506 if ((*s2 == '/' || *s2 == '\\') && !*s1)
512 /****************************************************************************
513 Ensure a remote path exists (make if necessary)
514 ***************************************************************************/
516 static BOOL ensurepath(char *fname)
518 /* *must* be called with buffer ready malloc'ed */
519 /* ensures path exists */
521 char *partpath, *ffname;
522 char *p=fname, *basehack;
524 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
526 partpath = string_create_s(strlen(fname));
527 ffname = string_create_s(strlen(fname));
529 if ((partpath == NULL) || (ffname == NULL)){
530 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
538 /* fname copied to ffname so can strtok */
540 safe_strcpy(ffname, fname, strlen(fname));
542 /* do a `basename' on ffname, so don't try and make file name directory */
543 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
548 p=strtok(ffname, "\\");
551 safe_strcat(partpath, p, strlen(fname) + 1);
553 if (!cli_chkpath(cli, partpath)) {
554 if (!cli_mkdir(cli, partpath)) {
555 DEBUG(0, ("Error mkdirhiering\n"));
558 DEBUG(3, ("mkdirhiering %s\n", partpath));
562 safe_strcat(partpath, "\\", strlen(fname) + 1);
563 p = strtok(NULL,"/\\");
569 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
574 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
575 memset(buf, 0, (size_t)bufsize);
576 while( !berr && padsize > 0 ) {
577 bytestowrite= (int)MIN(bufsize, padsize);
578 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
579 padsize -= bytestowrite;
585 static void do_setrattr(char *name, uint16 attr, int set)
589 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
591 if (set == ATTRSET) {
594 attr = oldattr & ~attr;
597 if (!cli_setatr(cli, name, attr, 0)) {
598 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
602 /****************************************************************************
603 append one remote file to the tar file
604 ***************************************************************************/
606 static void do_atar(char *rname,char *lname,file_info *finfo1)
609 SMB_BIG_UINT nread=0;
612 BOOL close_done = False;
613 BOOL shallitime=True;
615 int read_size = 65520;
618 struct timeval tp_start;
620 GetTimeOfDay(&tp_start);
622 ftype = '0'; /* An ordinary file ... */
625 finfo.size = finfo1 -> size;
626 finfo.mode = finfo1 -> mode;
627 finfo.uid = finfo1 -> uid;
628 finfo.gid = finfo1 -> gid;
629 finfo.mtime_ts = finfo1 -> mtime_ts;
630 finfo.atime_ts = finfo1 -> atime_ts;
631 finfo.ctime_ts = finfo1 -> ctime_ts;
632 finfo.name = finfo1 -> name;
634 finfo.size = def_finfo.size;
635 finfo.mode = def_finfo.mode;
636 finfo.uid = def_finfo.uid;
637 finfo.gid = def_finfo.gid;
638 finfo.mtime_ts = def_finfo.mtime_ts;
639 finfo.atime_ts = def_finfo.atime_ts;
640 finfo.ctime_ts = def_finfo.ctime_ts;
641 finfo.name = def_finfo.name;
645 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
646 (double)finfo.size));
648 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
653 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
658 DEBUG(0,("%s opening remote file %s (%s)\n",
659 cli_errstr(cli),rname, cur_dir));
663 finfo.name = string_create_s(strlen(rname));
664 if (finfo.name == NULL) {
665 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
669 safe_strcpy(finfo.name,rname, strlen(rname));
672 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
673 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
676 finfo.atime_ts = convert_time_t_to_timespec(atime);
677 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
678 finfo.ctime_ts = finfo.mtime_ts;
681 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
683 if (tar_inc && !(finfo.mode & aARCH)) {
684 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
686 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
687 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
689 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
690 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
693 BOOL wrote_tar_header = False;
695 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696 finfo.name, (double)finfo.size, lname));
698 while (nread < finfo.size && !close_done) {
700 DEBUG(3,("nread=%.0f\n",(double)nread));
702 datalen = cli_read(cli, fnum, data, nread, read_size);
705 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
711 /* Only if the first read succeeds, write out the tar header. */
712 if (!wrote_tar_header) {
713 /* write a tar header, don't bother with mode - just set to 100644 */
714 writetarheader(tarhandle, rname, finfo.size,
715 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
716 wrote_tar_header = True;
719 /* if file size has increased since we made file size query, truncate
720 read so tar header for this file will be correct.
723 if (nread > finfo.size) {
724 datalen -= nread - finfo.size;
725 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
726 finfo.name, (double)finfo.size));
729 /* add received bits of file to buffer - dotarbuf will
730 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
738 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
745 if (wrote_tar_header) {
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
749 (double)finfo.size, (int)nread));
750 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
751 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
761 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
766 cli_close(cli, fnum);
769 struct timeval tp_end;
772 /* if shallitime is true then we didn't skip */
773 if (tar_reset && !dry_run)
774 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
776 GetTimeOfDay(&tp_end);
777 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
778 get_total_time_ms += this_time;
779 get_total_size += finfo.size;
782 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
783 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
787 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
788 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
789 finfo.size / MAX(0.001, (1.024*this_time)),
790 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 /****************************************************************************
795 Append single file to tar file (or not)
796 ***************************************************************************/
798 static void do_tar(file_info *finfo)
802 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
805 /* Is it on the exclude list ? */
806 if (!tar_excl && clipn) {
809 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
811 pstrcpy(exclaim, cur_dir);
812 *(exclaim+strlen(exclaim)-1)='\0';
814 pstrcat(exclaim, "\\");
815 pstrcat(exclaim, finfo->name);
817 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
819 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
821 DEBUG(3,("Skipping file %s\n", exclaim));
826 if (finfo->mode & aDIR) {
827 pstring saved_curdir;
830 pstrcpy(saved_curdir, cur_dir);
832 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
833 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
834 (int)sizeof(cur_dir), (int)strlen(cur_dir),
835 (int)strlen(finfo->name), finfo->name, cur_dir));
837 pstrcat(cur_dir,finfo->name);
838 pstrcat(cur_dir,"\\");
840 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
842 /* write a tar directory, don't bother with mode - just set it to
844 writetarheader(tarhandle, cur_dir, 0, finfo->mtime_ts.tv_sec, "040755 \0", '5');
846 DEBUG(0,(" directory %s\n", cur_dir));
848 ntarf++; /* Make sure we have a file on there */
849 pstrcpy(mtar_mask,cur_dir);
850 pstrcat(mtar_mask,"*");
851 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
852 do_list(mtar_mask, attribute, do_tar, False, True);
853 pstrcpy(cur_dir,saved_curdir);
855 pstrcpy(rname,cur_dir);
856 pstrcat(rname,finfo->name);
857 do_atar(rname,finfo->name,finfo);
861 /****************************************************************************
862 Convert from UNIX to DOS file names
863 ***************************************************************************/
865 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
867 /* remove '.' from start of file name, convert from unix /'s to
868 * dos \'s in path. Kill any absolute path names. But only if first!
871 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
878 if (*fp == '\\' || *fp == '/') {
884 safe_strcpy(tptr, fp, l);
885 string_replace(tptr, '/', '\\');
888 /****************************************************************************
889 Move to the next block in the buffer, which may mean read in another set of
890 blocks. FIXME, we should allow more than one block to be skipped.
891 ****************************************************************************/
893 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
895 int bufread, total = 0;
897 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
901 if (*bufferp >= (ltarbuf + bufsiz)) {
903 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
906 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
907 * Fixes bug where read can return short if coming from
911 bufread = read(tarhandle, ltarbuf, bufsiz);
914 while (total < bufsiz) {
915 if (bufread < 0) { /* An error, return false */
916 return (total > 0 ? -2 : bufread);
924 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
928 DEBUG(5, ("Total bytes read ... %i\n", total));
936 /* Skip a file, even if it includes a long file name? */
937 static int skip_file(int skipsize)
939 int dsize = skipsize;
941 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
943 /* FIXME, we should skip more than one block at a time */
946 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
947 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
956 /*************************************************************
957 Get a file from the tar file and store it.
958 When this is called, tarbuf already contains the first
959 file block. This is a bit broken & needs fixing.
960 **************************************************************/
962 static int get_file(file_info2 finfo)
964 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
965 SMB_BIG_UINT rsize = 0;
967 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
969 if (ensurepath(finfo.name) &&
970 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
971 DEBUG(0, ("abandoning restore\n"));
975 /* read the blocks from the tar file and write to the remote file */
977 rsize = finfo.size; /* This is how much to write */
981 /* We can only write up to the end of the buffer */
982 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
983 dsize = MIN(dsize, rsize); /* Should be only what is left */
984 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
986 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
987 DEBUG(0, ("Error writing remote file\n"));
994 /* Now figure out how much to move in the buffer */
996 /* FIXME, we should skip more than one block at a time */
998 /* First, skip any initial part of the part written that is left over */
999 /* from the end of the first TBLOCK */
1001 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1002 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1005 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1006 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1012 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1013 * If the file being extracted is an exact multiple of
1014 * TBLOCK bytes then we don't want to extract the next
1015 * block from the tarfile here, as it will be done in
1016 * the caller of get_file().
1019 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1020 ((rsize == 0) && (dsize > TBLOCK))) {
1022 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1023 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1032 /* Now close the file ... */
1034 if (!cli_close(cli, fnum)) {
1035 DEBUG(0, ("Error closing remote file\n"));
1039 /* Now we update the creation date ... */
1040 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1042 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1043 if (tar_real_noisy) {
1044 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1045 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1050 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1054 /* Create a directory. We just ensure that the path exists and return as there
1055 is no file associated with a directory
1057 static int get_dir(file_info2 finfo)
1059 DEBUG(0, ("restore directory %s\n", finfo.name));
1061 if (!ensurepath(finfo.name)) {
1062 DEBUG(0, ("Problems creating directory\n"));
1069 /* Get a file with a long file name ... first file has file name, next file
1070 has the data. We only want the long file name, as the loop in do_tarput
1071 will deal with the rest.
1073 static char *get_longfilename(file_info2 finfo)
1075 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1077 int namesize = finfo.size + strlen(cur_dir) + 2;
1078 char *longname = (char *)SMB_MALLOC(namesize);
1079 int offset = 0, left = finfo.size;
1082 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1083 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1085 if (longname == NULL) {
1086 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1090 /* First, add cur_dir to the long file name */
1092 if (strlen(cur_dir) > 0) {
1093 strncpy(longname, cur_dir, namesize);
1094 offset = strlen(cur_dir);
1097 /* Loop through the blocks picking up the name */
1100 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1101 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1102 SAFE_FREE(longname);
1106 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1107 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1116 static void do_tarput(void)
1119 struct timeval tp_start;
1120 char *longfilename = NULL, linkflag;
1125 GetTimeOfDay(&tp_start);
1126 DEBUG(5, ("RJS do_tarput called ...\n"));
1128 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1130 /* Now read through those files ... */
1132 /* Get us to the next block, or the first block first time around */
1133 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1134 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1135 SAFE_FREE(longfilename);
1139 DEBUG(5, ("Reading the next header ...\n"));
1141 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1142 case -2: /* Hmm, not good, but not fatal */
1143 DEBUG(0, ("Skipping %s...\n", finfo.name));
1144 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1145 DEBUG(0, ("Short file, bailing out...\n"));
1151 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1154 case 0: /* chksum is zero - looks like an EOF */
1155 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1156 return; /* Hmmm, bad here ... */
1163 /* Now, do we have a long file name? */
1164 if (longfilename != NULL) {
1165 SAFE_FREE(finfo.name); /* Free the space already allocated */
1166 finfo.name = longfilename;
1167 longfilename = NULL;
1170 /* Well, now we have a header, process the file ... */
1171 /* Should we skip the file? We have the long name as well here */
1172 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1173 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1175 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1177 skip_file(finfo.size);
1181 /* We only get this far if we should process the file */
1182 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1184 case '0': /* Should use symbolic names--FIXME */
1186 * Skip to the next block first, so we can get the file, FIXME, should
1187 * be in get_file ...
1188 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1189 * Fixes bug where file size in tarfile is zero.
1191 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1192 DEBUG(0, ("Short file, bailing out...\n"));
1195 if (!get_file(finfo)) {
1196 DEBUG(0, ("Abandoning restore\n"));
1201 if (!get_dir(finfo)) {
1202 DEBUG(0, ("Abandoning restore \n"));
1207 SAFE_FREE(longfilename);
1208 longfilename = get_longfilename(finfo);
1209 if (!longfilename) {
1210 DEBUG(0, ("abandoning restore\n"));
1213 DEBUG(5, ("Long file name: %s\n", longfilename));
1217 skip_file(finfo.size); /* Don't handle these yet */
1224 * samba interactive commands
1227 /****************************************************************************
1229 ***************************************************************************/
1236 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1237 DEBUG(0, ("blocksize <n>\n"));
1242 if (block < 0 || block > 65535) {
1243 DEBUG(0, ("blocksize out of range"));
1248 DEBUG(2,("blocksize is now %d\n", blocksize));
1253 /****************************************************************************
1254 command to set incremental / reset mode
1255 ***************************************************************************/
1257 int cmd_tarmode(void)
1261 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1262 if (strequal(buf, "full"))
1264 else if (strequal(buf, "inc"))
1266 else if (strequal(buf, "reset"))
1268 else if (strequal(buf, "noreset"))
1270 else if (strequal(buf, "system"))
1272 else if (strequal(buf, "nosystem"))
1274 else if (strequal(buf, "hidden"))
1276 else if (strequal(buf, "nohidden"))
1278 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1280 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1283 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1286 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1287 tar_inc ? "incremental" : "full",
1288 tar_system ? "system" : "nosystem",
1289 tar_hidden ? "hidden" : "nohidden",
1290 tar_reset ? "reset" : "noreset",
1291 tar_noisy ? "verbose" : "quiet"));
1295 /****************************************************************************
1296 Feeble attrib command
1297 ***************************************************************************/
1299 int cmd_setmode(void)
1307 attra[0] = attra[1] = 0;
1309 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1310 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1314 pstrcpy(fname, cur_dir);
1315 pstrcat(fname, buf);
1317 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1329 attra[direct]|=aRONLY;
1332 attra[direct]|=aHIDDEN;
1335 attra[direct]|=aSYSTEM;
1338 attra[direct]|=aARCH;
1341 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1347 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1348 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1352 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1353 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1354 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1358 /****************************************************************************
1359 Principal command for creating / extracting
1360 ***************************************************************************/
1369 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1370 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1374 argl=toktocliplist(&argcl, NULL);
1375 if (!tar_parseargs(argcl, argl, buf, 0))
1378 ret = process_tar();
1383 /****************************************************************************
1384 Command line (option) version
1385 ***************************************************************************/
1387 int process_tar(void)
1404 if (clipn && tar_excl) {
1408 for (i=0; i<clipn; i++) {
1409 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1411 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1412 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1415 if (strrchr_m(cliplist[i], '\\')) {
1418 pstrcpy(saved_dir, cur_dir);
1420 if (*cliplist[i]=='\\') {
1421 pstrcpy(tarmac, cliplist[i]);
1423 pstrcpy(tarmac, cur_dir);
1424 pstrcat(tarmac, cliplist[i]);
1426 pstrcpy(cur_dir, tarmac);
1427 *(strrchr_m(cur_dir, '\\')+1)='\0';
1429 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1430 do_list(tarmac,attribute,do_tar, False, True);
1431 pstrcpy(cur_dir,saved_dir);
1433 pstrcpy(tarmac, cur_dir);
1434 pstrcat(tarmac, cliplist[i]);
1435 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1436 do_list(tarmac,attribute,do_tar, False, True);
1441 pstrcpy(mask,cur_dir);
1442 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1443 pstrcat(mask,"\\*");
1444 do_list(mask,attribute,do_tar,False, True);
1448 dotareof(tarhandle);
1452 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1453 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1457 if (must_free_cliplist) {
1459 for (i = 0; i < clipn; ++i) {
1460 SAFE_FREE(cliplist[i]);
1462 SAFE_FREE(cliplist);
1465 must_free_cliplist = False;
1470 /****************************************************************************
1471 Find a token (filename) in a clip list
1472 ***************************************************************************/
1474 static int clipfind(char **aret, int ret, char *tok)
1479 /* ignore leading slashes or dots in token */
1480 while(strchr_m("/\\.", *tok))
1486 /* ignore leading slashes or dots in list */
1487 while(strchr_m("/\\.", *pkey))
1490 if (!strslashcmp(pkey, tok))
1496 /****************************************************************************
1497 Read list of files to include from the file and initialize cliplist
1499 ***************************************************************************/
1501 static int read_inclusion_file(char *filename)
1503 XFILE *inclusion = NULL;
1504 char buf[PATH_MAX + 1];
1505 char *inclusion_buffer = NULL;
1506 int inclusion_buffer_size = 0;
1507 int inclusion_buffer_sofar = 0;
1514 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1515 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1516 /* XXX It would be better to include a reason for failure, but without
1517 * autoconf, it's hard to use strerror, sys_errlist, etc.
1519 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1523 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1524 if (inclusion_buffer == NULL) {
1525 inclusion_buffer_size = 1024;
1526 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1527 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1533 if (buf[strlen(buf)-1] == '\n') {
1534 buf[strlen(buf)-1] = '\0';
1537 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1538 inclusion_buffer_size *= 2;
1539 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1540 if (!inclusion_buffer) {
1541 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1542 inclusion_buffer_size));
1548 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1549 inclusion_buffer_sofar += strlen(buf) + 1;
1552 x_fclose(inclusion);
1555 /* Allocate an array of clipn + 1 char*'s for cliplist */
1556 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1557 if (cliplist == NULL) {
1558 DEBUG(0,("failure allocating memory for cliplist\n"));
1561 cliplist[clipn] = NULL;
1562 p = inclusion_buffer;
1563 for (i = 0; (! error) && (i < clipn); i++) {
1564 /* set current item to NULL so array will be null-terminated even if
1565 * malloc fails below. */
1567 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1568 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1571 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1572 cliplist[i] = tmpstr;
1573 if ((p = strchr_m(p, '\000')) == NULL) {
1574 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1580 must_free_cliplist = True;
1584 SAFE_FREE(inclusion_buffer);
1588 /* We know cliplist is always null-terminated */
1589 for (pp = cliplist; *pp; ++pp) {
1592 SAFE_FREE(cliplist);
1594 must_free_cliplist = False;
1599 /* cliplist and its elements are freed at the end of process_tar. */
1603 /****************************************************************************
1604 Parse tar arguments. Sets tar_type, tar_excl, etc.
1605 ***************************************************************************/
1607 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1609 int newOptind = Optind;
1610 char tar_clipfl='\0';
1612 /* Reset back to defaults - could be from interactive version
1613 * reset mode and archive mode left as they are though
1625 if (tar_type=='c') {
1626 printf("Tar must be followed by only one of c or x.\n");
1632 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1633 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1645 DEBUG(0,("Option N must be followed by valid file name\n"));
1648 SMB_STRUCT_STAT stbuf;
1650 if (sys_stat(argv[Optind], &stbuf) == 0) {
1651 newer_than = stbuf.st_mtime;
1652 DEBUG(1,("Getting files newer than %s",
1653 time_to_asc(newer_than)));
1657 DEBUG(0,("Error setting newer-than time\n"));
1670 DEBUG(0,("Only one of I,X,F must be specified\n"));
1677 DEBUG(0,("Only one of I,X,F must be specified\n"));
1684 DEBUG(0,("Only one of I,X,F must be specified\n"));
1690 DEBUG(0, ("tar_re_search set\n"));
1691 tar_re_search = True;
1694 if (tar_type == 'c') {
1695 DEBUG(0, ("dry_run set\n"));
1698 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1703 DEBUG(0,("Unknown tar option\n"));
1709 printf("Option T must be followed by one of c or x.\n");
1713 /* tar_excl is true if cliplist lists files to be included.
1714 * Both 'I' and 'F' mean include. */
1715 tar_excl=tar_clipfl!='X';
1717 if (tar_clipfl=='F') {
1718 if (argc-Optind-1 != 1) {
1719 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1723 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1724 if (! read_inclusion_file(argv[Optind+1])) {
1727 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1732 cliplist=argv+Optind+1;
1733 clipn=argc-Optind-1;
1736 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1737 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1741 for (clipcount = 0; clipcount < clipn; clipcount++) {
1743 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1745 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1746 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1751 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1752 tmplist[clipcount] = tmpstr;
1753 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1755 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1759 must_free_cliplist = True;
1764 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1765 /* Doing regular expression seaches not from an inclusion file. */
1766 clipn=argc-Optind-1;
1767 cliplist=argv+Optind+1;
1771 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1772 /* Sets tar handle to either 0 or 1, as appropriate */
1773 tarhandle=(tar_type=='c');
1775 * Make sure that dbf points to stderr if we are using stdout for
1778 if (tarhandle == 1) {
1781 if (!argv[Optind]) {
1782 DEBUG(0,("Must specify tar filename\n"));
1785 if (!strcmp(argv[Optind], "-")) {
1790 if (tar_type=='c' && dry_run) {
1792 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1793 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1794 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));