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, see <http://www.gnu.org/licenses/>.
20 /* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
23 1. Restore can now restore files with long file names
24 2. Save now saves directory information so that we can restore
25 directory creation times
26 3. tar now accepts both UNIX path names and DOS path names. I prefer
27 those lovely /'s to those UGLY \'s :-)
28 4. the files to exclude can be specified as a regular expression by adding
29 an r flag to the other tar flags. Eg:
31 -TcrX file.tar "*.(obj|exe)"
33 will skip all .obj and .exe files
39 #include "client/client_proto.h"
41 static int clipfind(char **aret, int ret, char *tok);
43 typedef struct file_info_struct file_info2;
45 struct file_info_struct {
50 /* These times are normally kept in GMT */
51 struct timespec mtime_ts;
52 struct timespec atime_ts;
53 struct timespec ctime_ts;
54 char *name; /* This is dynamically allocated */
55 file_info2 *next, *prev; /* Used in the stack ... */
63 #define SEPARATORS " \t\n\r"
64 extern time_t newer_than;
65 extern struct cli_state *cli;
67 /* These defines are for the do_setrattr routine, to indicate
68 * setting and reseting of file attributes in the function call */
72 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
74 #ifndef CLIENT_TIMEOUT
75 #define CLIENT_TIMEOUT (30*1000)
78 static char *tarbuf, *buffer_p;
79 static int tp, ntarf, tbufsiz;
81 /* Incremental mode */
82 static bool tar_inc=False;
83 /* Reset archive bit */
84 static bool tar_reset=False;
85 /* Include / exclude mode (true=include, false=exclude) */
86 static bool tar_excl=True;
87 /* use regular expressions for search on file names */
88 static bool tar_re_search=False;
89 /* Do not dump anything, just calculate sizes */
90 static bool dry_run=False;
91 /* Dump files with System attribute */
92 static bool tar_system=True;
93 /* Dump files with Hidden attribute */
94 static bool tar_hidden=True;
95 /* Be noisy - make a catalogue */
96 static bool tar_noisy=True;
97 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
100 static char **cliplist=NULL;
102 static bool must_free_cliplist = False;
103 extern const char *cmd_ptr;
105 extern bool lowercase;
107 extern bool readbraw_supported;
109 extern int get_total_time_ms;
110 extern int get_total_size;
112 static int blocksize=20;
113 static int tarhandle;
115 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
116 const char *amode, unsigned char ftype);
117 static void do_atar(const char *rname_in,char *lname,file_info *finfo1);
118 static void do_tar(file_info *finfo, const char *dir);
119 static void oct_it(uint64_t value, int ndgs, char *p);
120 static void fixtarname(char *tptr, const char *fp, size_t l);
121 static int dotarbuf(int f, char *b, int n);
122 static void dozerobuf(int f, int n);
123 static void dotareof(int f);
124 static void initarbuf(void);
126 /* restore functions */
127 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
128 static long unoct(char *p, int ndgs);
129 static void do_tarput(void);
130 static void unfixtarname(char *tptr, char *fp, int l, bool first);
133 * tar specific utitlities
136 /*******************************************************************
137 Create a string of size size+1 (for the null)
138 *******************************************************************/
140 static char *string_create_s(int size)
144 tmp = (char *)SMB_MALLOC(size+1);
147 DEBUG(0, ("Out of memory in string_create_s\n"));
153 /****************************************************************************
154 Write a tar header to buffer
155 ****************************************************************************/
157 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
158 const char *amode, unsigned char ftype)
164 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
166 memset(hb.dummy, 0, sizeof(hb.dummy));
169 /* We will be prepending a '.' in fixtarheader so use +2 to
170 * take care of the . and terminating zero. JRA.
173 /* write a GNU tar style long header */
175 b = (char *)SMB_MALLOC(l+TBLOCK+100);
177 DEBUG(0,("out of memory\n"));
180 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
181 memset(b, 0, l+TBLOCK+100);
182 fixtarname(b, aname, l+2);
184 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
185 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
189 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
192 strlower_m(hb.dbuf.name);
194 /* write out a "standard" tar format header */
196 hb.dbuf.name[NAMSIZ-1]='\0';
197 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
198 oct_it((uint64_t)0, 8, hb.dbuf.uid);
199 oct_it((uint64_t)0, 8, hb.dbuf.gid);
200 oct_it((uint64_t) size, 13, hb.dbuf.size);
201 if (size > (uint64_t)077777777777LL) {
202 /* This is a non-POSIX compatible extention to store files
205 memset(hb.dbuf.size, 0, 4);
207 for (i = 8, jp=(char*)&size; i; i--)
208 hb.dbuf.size[i+3] = *(jp++);
210 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
211 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
212 memset(hb.dbuf.linkname, 0, NAMSIZ);
213 hb.dbuf.linkflag=ftype;
215 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
218 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
219 hb.dbuf.chksum[6] = '\0';
221 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
224 /****************************************************************************
225 Read a tar header into a hblock structure, and validate
226 ***************************************************************************/
228 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
235 * read in a "standard" tar format header - we're not that interested
236 * in that many fields, though
239 /* check the checksum */
240 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
246 /* compensate for blanks in chksum header */
247 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
250 chk += ' ' * sizeof(hb->dbuf.chksum);
252 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
254 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
255 chk, fchk, hb->dbuf.chksum));
258 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
259 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
263 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
264 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
268 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
270 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
271 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
272 strlen(hb->dbuf.name) + 1, True);
274 /* can't handle some links at present */
275 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
276 if (hb->dbuf.linkflag == 0) {
277 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
280 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
281 /* Do nothing here at the moment. do_tarput will handle this
282 as long as the longlink gets back to it, as it has to advance
283 the buffer pointer, etc */
285 DEBUG(0, ("this tar file appears to contain some kind \
286 of link other than a GNUtar Longlink - ignoring\n"));
292 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
293 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
296 finfo->mode=0; /* we don't care about mode at the moment, we'll
297 * just make it a regular file */
301 * Bug fix by richard@sj.co.uk
303 * REC: restore times correctly (as does tar)
304 * We only get the modification time of the file; set the creation time
305 * from the mod. time, and the access time to current time
307 finfo->mtime_ts = finfo->ctime_ts =
308 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
309 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
310 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 /****************************************************************************
316 Write out the tar buffer to tape or wherever
317 ****************************************************************************/
319 static int dotarbuf(int f, char *b, int n)
326 /* This routine and the next one should be the only ones that do write()s */
327 if (tp + n >= tbufsiz) {
331 memcpy(tarbuf + tp, b, diff);
332 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
337 while (n >= tbufsiz) {
338 fail=fail && (1 + sys_write(f, b, tbufsiz));
345 memcpy(tarbuf+tp, b, n);
349 return(fail ? writ : 0);
352 /****************************************************************************
353 Write zeros to buffer / tape
354 ****************************************************************************/
356 static void dozerobuf(int f, int n)
358 /* short routine just to write out n zeros to buffer -
359 * used to round files to nearest block
360 * and to do tar EOFs */
365 if (n+tp >= tbufsiz) {
366 memset(tarbuf+tp, 0, tbufsiz-tp);
367 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
368 DEBUG(0, ("dozerobuf: sys_write fail\n"));
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
373 memset(tarbuf+tp, 0, n);
378 /****************************************************************************
380 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1) {
408 DEBUG(0, ("Couldn't stat file handle\n"));
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
415 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
416 if (sys_write(f, tarbuf, towrite) != towrite) {
417 DEBUG(0,("dotareof: sys_write fail\n"));
422 /****************************************************************************
423 (Un)mangle DOS pathname, make nonabsolute
424 ****************************************************************************/
426 static void fixtarname(char *tptr, const char *fp, size_t l)
428 /* add a '.' to start of file name, convert from ugly dos \'s in path
429 * to lovely unix /'s :-} */
433 StrnCpy(tptr, fp, l-1);
434 string_replace(tptr, '\\', '/');
437 /****************************************************************************
438 Convert from decimal to octal string
439 ****************************************************************************/
441 static void oct_it (uint64_t value, int ndgs, char *p)
443 /* Converts long to octal string, pads with leading zeros */
445 /* skip final null, but do final space */
449 /* Loop does at least one digit */
451 p[--ndgs] = '0' + (char) (value & 7);
453 } while (ndgs > 0 && value != 0);
455 /* Do leading zeros */
460 /****************************************************************************
461 Convert from octal string to long
462 ***************************************************************************/
464 static long unoct(char *p, int ndgs)
467 /* Converts octal string to long, ignoring any non-digit */
470 if (isdigit((int)*p))
471 value = (value << 3) | (long) (*p - '0');
479 /****************************************************************************
480 Compare two strings in a slash insensitive way, allowing s1 to match s2
481 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
482 a file in any subdirectory of s1, declare a match.
483 ***************************************************************************/
485 static int strslashcmp(char *s1, char *s2)
489 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
490 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
494 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
497 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
500 /* ignore trailing slash on s1 */
501 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
504 /* check for s1 is an "initial" string of s2 */
505 if ((*s2 == '/' || *s2 == '\\') && !*s1)
511 /****************************************************************************
512 Ensure a remote path exists (make if necessary)
513 ***************************************************************************/
515 static bool ensurepath(const char *fname)
517 /* *must* be called with buffer ready malloc'ed */
518 /* ensures path exists */
520 char *partpath, *ffname;
525 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
527 partpath = string_create_s(strlen(fname));
528 ffname = string_create_s(strlen(fname));
530 if ((partpath == NULL) || (ffname == NULL)){
531 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
539 /* fname copied to ffname so can strtok_r */
541 safe_strcpy(ffname, fname, strlen(fname));
543 /* do a `basename' on ffname, so don't try and make file name directory */
544 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
552 p=strtok_r(ffname, "\\", &saveptr);
555 safe_strcat(partpath, p, strlen(fname) + 1);
557 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
558 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
561 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
564 DEBUG(3, ("mkdirhiering %s\n", partpath));
568 safe_strcat(partpath, "\\", strlen(fname) + 1);
569 p = strtok_r(NULL, "/\\", &saveptr);
577 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
582 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
583 memset(buf, 0, (size_t)bufsize);
584 while( !berr && padsize > 0 ) {
585 bytestowrite= (int)MIN(bufsize, padsize);
586 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
587 padsize -= bytestowrite;
593 static void do_setrattr(char *name, uint16 attr, int set)
597 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
601 if (set == ATTRSET) {
604 attr = oldattr & ~attr;
607 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
608 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
612 /****************************************************************************
613 append one remote file to the tar file
614 ***************************************************************************/
616 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
618 uint16_t fnum = (uint16_t)-1;
622 bool shallitime=True;
624 int read_size = 65520;
627 TALLOC_CTX *ctx = talloc_stackframe();
629 struct timeval tp_start;
631 GetTimeOfDay(&tp_start);
633 data = SMB_MALLOC_ARRAY(char, read_size);
635 DEBUG(0,("do_atar: out of memory.\n"));
639 ftype = '0'; /* An ordinary file ... */
643 finfo.size = finfo1 -> size;
644 finfo.mode = finfo1 -> mode;
645 finfo.uid = finfo1 -> uid;
646 finfo.gid = finfo1 -> gid;
647 finfo.mtime_ts = finfo1 -> mtime_ts;
648 finfo.atime_ts = finfo1 -> atime_ts;
649 finfo.ctime_ts = finfo1 -> ctime_ts;
652 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
653 (double)finfo.size));
655 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
660 rname = clean_name(ctx, rname_in);
665 if (!NT_STATUS_IS_OK(cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum))) {
666 DEBUG(0,("%s opening remote file %s (%s)\n",
667 cli_errstr(cli),rname, client_get_cur_dir()));
671 finfo.name = string_create_s(strlen(rname));
672 if (finfo.name == NULL) {
673 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
677 safe_strcpy(finfo.name,rname, strlen(rname));
679 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
681 if (tar_inc && !(finfo.mode & aARCH)) {
682 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
684 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
685 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
687 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
688 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 bool wrote_tar_header = False;
693 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
694 finfo.name, (double)finfo.size, lname));
698 DEBUG(3,("nread=%.0f\n",(double)nread));
700 datalen = cli_read(cli, fnum, data, nread, read_size);
703 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
709 /* Only if the first read succeeds, write out the tar header. */
710 if (!wrote_tar_header) {
711 /* write a tar header, don't bother with mode - just set to 100644 */
712 writetarheader(tarhandle, rname, finfo.size,
713 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
714 wrote_tar_header = True;
717 /* if file size has increased since we made file size query, truncate
718 read so tar header for this file will be correct.
721 if (nread > finfo.size) {
722 datalen -= nread - finfo.size;
723 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
724 finfo.name, (double)finfo.size));
727 /* add received bits of file to buffer - dotarbuf will
728 * write out in 512 byte intervals */
730 if (dotarbuf(tarhandle,data,datalen) != datalen) {
731 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
735 if ( (datalen == 0) && (finfo.size != 0) ) {
736 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
741 } while ( nread < finfo.size );
743 if (wrote_tar_header) {
744 /* pad tar file with zero's if we couldn't get entire file */
745 if (nread < finfo.size) {
746 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
747 (double)finfo.size, (int)nread));
748 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread))
749 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
752 /* round tar file to nearest block */
753 if (finfo.size % TBLOCK)
754 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
756 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
764 cli_close(cli, fnum);
768 struct timeval tp_end;
771 /* if shallitime is true then we didn't skip */
772 if (tar_reset && !dry_run)
773 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
775 GetTimeOfDay(&tp_end);
776 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
777 get_total_time_ms += this_time;
778 get_total_size += finfo.size;
781 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo.size / MAX(0.001, (1.024*this_time)),
789 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 if (fnum != (uint16_t)-1) {
795 cli_close(cli, fnum);
802 /****************************************************************************
803 Append single file to tar file (or not)
804 ***************************************************************************/
806 static void do_tar(file_info *finfo, const char *dir)
808 TALLOC_CTX *ctx = talloc_stackframe();
810 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
813 /* Is it on the exclude list ? */
814 if (!tar_excl && clipn) {
817 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
819 exclaim = talloc_asprintf(ctx,
821 client_get_cur_dir(),
827 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
829 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
831 && mask_match_list(exclaim, cliplist, clipn,
832 PROTOCOL_NONE, True))) {
833 DEBUG(3,("Skipping file %s\n", exclaim));
834 TALLOC_FREE(exclaim);
837 TALLOC_FREE(exclaim);
840 if (finfo->mode & aDIR) {
841 char *saved_curdir = NULL;
843 char *mtar_mask = NULL;
845 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
850 DEBUG(5, ("strlen(cur_dir)=%d, \
851 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
852 (int)strlen(saved_curdir),
853 (int)strlen(finfo->name), finfo->name, saved_curdir));
855 new_cd = talloc_asprintf(ctx,
857 client_get_cur_dir(),
862 client_set_cur_dir(new_cd);
864 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
866 /* write a tar directory, don't bother with mode - just
868 writetarheader(tarhandle, client_get_cur_dir(), 0,
869 finfo->mtime_ts.tv_sec, "040755 \0", '5');
871 DEBUG(0,(" directory %s\n",
872 client_get_cur_dir()));
874 ntarf++; /* Make sure we have a file on there */
875 mtar_mask = talloc_asprintf(ctx,
877 client_get_cur_dir());
881 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
882 do_list(mtar_mask, attribute, do_tar, False, True);
883 client_set_cur_dir(saved_curdir);
884 TALLOC_FREE(saved_curdir);
886 TALLOC_FREE(mtar_mask);
888 char *rname = talloc_asprintf(ctx,
890 client_get_cur_dir(),
895 do_atar(rname,finfo->name,finfo);
900 /****************************************************************************
901 Convert from UNIX to DOS file names
902 ***************************************************************************/
904 static void unfixtarname(char *tptr, char *fp, int l, bool first)
906 /* remove '.' from start of file name, convert from unix /'s to
907 * dos \'s in path. Kill any absolute path names. But only if first!
910 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
917 if (*fp == '\\' || *fp == '/') {
923 safe_strcpy(tptr, fp, l);
924 string_replace(tptr, '/', '\\');
927 /****************************************************************************
928 Move to the next block in the buffer, which may mean read in another set of
929 blocks. FIXME, we should allow more than one block to be skipped.
930 ****************************************************************************/
932 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
934 int bufread, total = 0;
936 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
940 if (*bufferp >= (ltarbuf + bufsiz)) {
942 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
945 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
946 * Fixes bug where read can return short if coming from
950 bufread = read(tarhandle, ltarbuf, bufsiz);
953 while (total < bufsiz) {
954 if (bufread < 0) { /* An error, return false */
955 return (total > 0 ? -2 : bufread);
963 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
967 DEBUG(5, ("Total bytes read ... %i\n", total));
975 /* Skip a file, even if it includes a long file name? */
976 static int skip_file(int skipsize)
978 int dsize = skipsize;
980 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
982 /* FIXME, we should skip more than one block at a time */
985 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
986 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
995 /*************************************************************
996 Get a file from the tar file and store it.
997 When this is called, tarbuf already contains the first
998 file block. This is a bit broken & needs fixing.
999 **************************************************************/
1001 static int get_file(file_info2 finfo)
1004 int pos = 0, dsize = 0, bpos = 0;
1007 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1009 if (ensurepath(finfo.name) &&
1010 (!NT_STATUS_IS_OK(cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE,&fnum)))) {
1011 DEBUG(0, ("abandoning restore\n"));
1015 /* read the blocks from the tar file and write to the remote file */
1017 rsize = finfo.size; /* This is how much to write */
1021 /* We can only write up to the end of the buffer */
1022 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1023 dsize = MIN(dsize, rsize); /* Should be only what is left */
1024 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1026 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1027 DEBUG(0, ("Error writing remote file\n"));
1034 /* Now figure out how much to move in the buffer */
1036 /* FIXME, we should skip more than one block at a time */
1038 /* First, skip any initial part of the part written that is left over */
1039 /* from the end of the first TBLOCK */
1041 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1042 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1045 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1046 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1052 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053 * If the file being extracted is an exact multiple of
1054 * TBLOCK bytes then we don't want to extract the next
1055 * block from the tarfile here, as it will be done in
1056 * the caller of get_file().
1059 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060 ((rsize == 0) && (dsize > TBLOCK))) {
1062 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1072 /* Now close the file ... */
1074 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1075 DEBUG(0, ("Error %s closing remote file\n",
1080 /* Now we update the creation date ... */
1081 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1083 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1084 if (tar_real_noisy) {
1085 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1086 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1091 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1095 /* Create a directory. We just ensure that the path exists and return as there
1096 is no file associated with a directory
1098 static int get_dir(file_info2 finfo)
1100 DEBUG(0, ("restore directory %s\n", finfo.name));
1102 if (!ensurepath(finfo.name)) {
1103 DEBUG(0, ("Problems creating directory\n"));
1110 /* Get a file with a long file name ... first file has file name, next file
1111 has the data. We only want the long file name, as the loop in do_tarput
1112 will deal with the rest.
1114 static char *get_longfilename(file_info2 finfo)
1116 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1118 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1119 char *longname = (char *)SMB_MALLOC(namesize);
1120 int offset = 0, left = finfo.size;
1123 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1124 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1126 if (longname == NULL) {
1127 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1131 /* First, add cur_dir to the long file name */
1133 if (strlen(client_get_cur_dir()) > 0) {
1134 strncpy(longname, client_get_cur_dir(), namesize);
1135 offset = strlen(client_get_cur_dir());
1138 /* Loop through the blocks picking up the name */
1141 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1142 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1143 SAFE_FREE(longname);
1147 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1148 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1157 static void do_tarput(void)
1160 struct timeval tp_start;
1161 char *longfilename = NULL, linkflag;
1166 GetTimeOfDay(&tp_start);
1167 DEBUG(5, ("RJS do_tarput called ...\n"));
1169 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1171 /* Now read through those files ... */
1173 /* Get us to the next block, or the first block first time around */
1174 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1175 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1176 SAFE_FREE(longfilename);
1180 DEBUG(5, ("Reading the next header ...\n"));
1182 switch (readtarheader((union hblock *) buffer_p,
1183 &finfo, client_get_cur_dir())) {
1184 case -2: /* Hmm, not good, but not fatal */
1185 DEBUG(0, ("Skipping %s...\n", finfo.name));
1186 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1187 DEBUG(0, ("Short file, bailing out...\n"));
1193 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1196 case 0: /* chksum is zero - looks like an EOF */
1197 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1198 return; /* Hmmm, bad here ... */
1205 /* Now, do we have a long file name? */
1206 if (longfilename != NULL) {
1207 SAFE_FREE(finfo.name); /* Free the space already allocated */
1208 finfo.name = longfilename;
1209 longfilename = NULL;
1212 /* Well, now we have a header, process the file ... */
1213 /* Should we skip the file? We have the long name as well here */
1214 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1216 && mask_match_list(finfo.name, cliplist,
1217 clipn, PROTOCOL_NONE,
1220 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1222 skip_file(finfo.size);
1226 /* We only get this far if we should process the file */
1227 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1229 case '0': /* Should use symbolic names--FIXME */
1231 * Skip to the next block first, so we can get the file, FIXME, should
1232 * be in get_file ...
1233 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1234 * Fixes bug where file size in tarfile is zero.
1236 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1237 DEBUG(0, ("Short file, bailing out...\n"));
1240 if (!get_file(finfo)) {
1241 DEBUG(0, ("Abandoning restore\n"));
1246 if (!get_dir(finfo)) {
1247 DEBUG(0, ("Abandoning restore \n"));
1252 SAFE_FREE(longfilename);
1253 longfilename = get_longfilename(finfo);
1254 if (!longfilename) {
1255 DEBUG(0, ("abandoning restore\n"));
1258 DEBUG(5, ("Long file name: %s\n", longfilename));
1262 skip_file(finfo.size); /* Don't handle these yet */
1269 * samba interactive commands
1272 /****************************************************************************
1274 ***************************************************************************/
1278 TALLOC_CTX *ctx = talloc_tos();
1282 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1283 DEBUG(0, ("blocksize <n>\n"));
1288 if (block < 0 || block > 65535) {
1289 DEBUG(0, ("blocksize out of range"));
1294 DEBUG(2,("blocksize is now %d\n", blocksize));
1298 /****************************************************************************
1299 command to set incremental / reset mode
1300 ***************************************************************************/
1302 int cmd_tarmode(void)
1304 TALLOC_CTX *ctx = talloc_tos();
1307 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1308 if (strequal(buf, "full"))
1310 else if (strequal(buf, "inc"))
1312 else if (strequal(buf, "reset"))
1314 else if (strequal(buf, "noreset"))
1316 else if (strequal(buf, "system"))
1318 else if (strequal(buf, "nosystem"))
1320 else if (strequal(buf, "hidden"))
1322 else if (strequal(buf, "nohidden"))
1324 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1326 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1329 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1333 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334 tar_inc ? "incremental" : "full",
1335 tar_system ? "system" : "nosystem",
1336 tar_hidden ? "hidden" : "nohidden",
1337 tar_reset ? "reset" : "noreset",
1338 tar_noisy ? "verbose" : "quiet"));
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1346 int cmd_setmode(void)
1348 TALLOC_CTX *ctx = talloc_tos();
1355 attra[0] = attra[1] = 0;
1357 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1358 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1362 fname = talloc_asprintf(ctx,
1364 client_get_cur_dir(),
1370 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1382 attra[direct]|=aRONLY;
1385 attra[direct]|=aHIDDEN;
1388 attra[direct]|=aSYSTEM;
1391 attra[direct]|=aARCH;
1394 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1400 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1401 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1405 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1406 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1407 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1412 Convert list of tokens to array; dependent on above routine.
1413 Uses the global cmd_ptr from above - bit of a hack.
1416 static char **toktocliplist(int *ctok, const char *sep)
1418 char *s=(char *)cmd_ptr;
1425 while(*s && strchr_m(sep,*s))
1434 while(*s && (!strchr_m(sep,*s)))
1436 while(*s && strchr_m(sep,*s))
1443 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1460 /****************************************************************************
1461 Principal command for creating / extracting
1462 ***************************************************************************/
1466 TALLOC_CTX *ctx = talloc_tos();
1472 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1473 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1477 argl=toktocliplist(&argcl, NULL);
1478 if (!tar_parseargs(argcl, argl, buf, 0)) {
1483 ret = process_tar();
1488 /****************************************************************************
1489 Command line (option) version
1490 ***************************************************************************/
1492 int process_tar(void)
1494 TALLOC_CTX *ctx = talloc_tos();
1510 if (clipn && tar_excl) {
1512 char *tarmac = NULL;
1514 for (i=0; i<clipn; i++) {
1515 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1517 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1518 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1521 if (strrchr_m(cliplist[i], '\\')) {
1524 char *saved_dir = talloc_strdup(ctx,
1525 client_get_cur_dir());
1530 if (*cliplist[i]=='\\') {
1531 tarmac = talloc_strdup(ctx,
1534 tarmac = talloc_asprintf(ctx,
1536 client_get_cur_dir(),
1543 * Strip off the last \\xxx
1544 * xxx element of tarmac to set
1545 * it as current directory.
1547 p = strrchr_m(tarmac, '\\');
1554 client_set_cur_dir(tarmac);
1557 * Restore the character we
1564 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1565 do_list(tarmac,attribute,do_tar, False, True);
1567 client_set_cur_dir(saved_dir);
1569 TALLOC_FREE(saved_dir);
1570 TALLOC_FREE(tarmac);
1572 tarmac = talloc_asprintf(ctx,
1574 client_get_cur_dir(),
1579 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1580 do_list(tarmac,attribute,do_tar, False, True);
1581 TALLOC_FREE(tarmac);
1585 char *mask = talloc_asprintf(ctx,
1587 client_get_cur_dir());
1591 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1592 do_list(mask,attribute,do_tar,False, True);
1597 dotareof(tarhandle);
1602 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1603 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1607 if (must_free_cliplist) {
1609 for (i = 0; i < clipn; ++i) {
1610 SAFE_FREE(cliplist[i]);
1612 SAFE_FREE(cliplist);
1615 must_free_cliplist = False;
1620 /****************************************************************************
1621 Find a token (filename) in a clip list
1622 ***************************************************************************/
1624 static int clipfind(char **aret, int ret, char *tok)
1629 /* ignore leading slashes or dots in token */
1630 while(strchr_m("/\\.", *tok))
1636 /* ignore leading slashes or dots in list */
1637 while(strchr_m("/\\.", *pkey))
1640 if (!strslashcmp(pkey, tok))
1646 /****************************************************************************
1647 Read list of files to include from the file and initialize cliplist
1649 ***************************************************************************/
1651 static int read_inclusion_file(char *filename)
1653 XFILE *inclusion = NULL;
1654 char buf[PATH_MAX + 1];
1655 char *inclusion_buffer = NULL;
1656 int inclusion_buffer_size = 0;
1657 int inclusion_buffer_sofar = 0;
1664 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1665 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1666 /* XXX It would be better to include a reason for failure, but without
1667 * autoconf, it's hard to use strerror, sys_errlist, etc.
1669 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1673 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1674 if (inclusion_buffer == NULL) {
1675 inclusion_buffer_size = 1024;
1676 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1677 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1683 if (buf[strlen(buf)-1] == '\n') {
1684 buf[strlen(buf)-1] = '\0';
1687 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1688 inclusion_buffer_size *= 2;
1689 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1690 if (!inclusion_buffer) {
1691 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1692 inclusion_buffer_size));
1698 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1699 inclusion_buffer_sofar += strlen(buf) + 1;
1702 x_fclose(inclusion);
1705 /* Allocate an array of clipn + 1 char*'s for cliplist */
1706 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1707 if (cliplist == NULL) {
1708 DEBUG(0,("failure allocating memory for cliplist\n"));
1711 cliplist[clipn] = NULL;
1712 p = inclusion_buffer;
1713 for (i = 0; (! error) && (i < clipn); i++) {
1714 /* set current item to NULL so array will be null-terminated even if
1715 * malloc fails below. */
1717 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1718 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1721 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1722 cliplist[i] = tmpstr;
1723 if ((p = strchr_m(p, '\000')) == NULL) {
1724 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1730 must_free_cliplist = True;
1734 SAFE_FREE(inclusion_buffer);
1738 /* We know cliplist is always null-terminated */
1739 for (pp = cliplist; *pp; ++pp) {
1742 SAFE_FREE(cliplist);
1744 must_free_cliplist = False;
1749 /* cliplist and its elements are freed at the end of process_tar. */
1753 /****************************************************************************
1754 Parse tar arguments. Sets tar_type, tar_excl, etc.
1755 ***************************************************************************/
1757 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1759 int newOptind = Optind;
1760 char tar_clipfl='\0';
1762 /* Reset back to defaults - could be from interactive version
1763 * reset mode and archive mode left as they are though
1775 if (tar_type=='c') {
1776 printf("Tar must be followed by only one of c or x.\n");
1782 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1783 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1795 DEBUG(0,("Option N must be followed by valid file name\n"));
1798 SMB_STRUCT_STAT stbuf;
1800 if (sys_stat(argv[Optind], &stbuf) == 0) {
1801 newer_than = convert_timespec_to_time_t(
1803 DEBUG(1,("Getting files newer than %s",
1804 time_to_asc(newer_than)));
1808 DEBUG(0,("Error setting newer-than time\n"));
1821 DEBUG(0,("Only one of I,X,F must be specified\n"));
1828 DEBUG(0,("Only one of I,X,F must be specified\n"));
1835 DEBUG(0,("Only one of I,X,F must be specified\n"));
1841 DEBUG(0, ("tar_re_search set\n"));
1842 tar_re_search = True;
1845 if (tar_type == 'c') {
1846 DEBUG(0, ("dry_run set\n"));
1849 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1854 DEBUG(0,("Unknown tar option\n"));
1860 printf("Option T must be followed by one of c or x.\n");
1864 /* tar_excl is true if cliplist lists files to be included.
1865 * Both 'I' and 'F' mean include. */
1866 tar_excl=tar_clipfl!='X';
1868 if (tar_clipfl=='F') {
1869 if (argc-Optind-1 != 1) {
1870 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1874 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1875 if (! read_inclusion_file(argv[Optind+1])) {
1878 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1883 cliplist=argv+Optind+1;
1884 clipn=argc-Optind-1;
1887 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1888 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1892 for (clipcount = 0; clipcount < clipn; clipcount++) {
1894 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1896 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1897 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1902 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1903 tmplist[clipcount] = tmpstr;
1904 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1906 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1910 must_free_cliplist = True;
1915 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1916 /* Doing regular expression seaches not from an inclusion file. */
1917 clipn=argc-Optind-1;
1918 cliplist=argv+Optind+1;
1922 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1923 /* Sets tar handle to either 0 or 1, as appropriate */
1924 tarhandle=(tar_type=='c');
1926 * Make sure that dbf points to stderr if we are using stdout for
1929 if (tarhandle == 1) {
1932 if (!argv[Optind]) {
1933 DEBUG(0,("Must specify tar filename\n"));
1936 if (!strcmp(argv[Optind], "-")) {
1941 if (tar_type=='c' && dry_run) {
1943 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1944 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1945 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));