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 2 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 */
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);
204 if (size > (SMB_BIG_UINT)077777777777LL) {
206 /* This is a non-POSIX compatible extention to store files
209 memset(hb.dbuf.size, 0, 4);
211 for (i = 8, jp=(char*)&size; i; i--)
212 hb.dbuf.size[i+3] = *(jp++);
214 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
215 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
216 memset(hb.dbuf.linkname, 0, NAMSIZ);
217 hb.dbuf.linkflag=ftype;
219 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
222 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
223 hb.dbuf.chksum[6] = '\0';
225 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
228 /****************************************************************************
229 Read a tar header into a hblock structure, and validate
230 ***************************************************************************/
232 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
239 * read in a "standard" tar format header - we're not that interested
240 * in that many fields, though
243 /* check the checksum */
244 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
250 /* compensate for blanks in chksum header */
251 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
254 chk += ' ' * sizeof(hb->dbuf.chksum);
256 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
258 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
259 chk, fchk, hb->dbuf.chksum));
262 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
263 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
267 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
268 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
272 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
274 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
275 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
276 strlen(hb->dbuf.name) + 1, True);
278 /* can't handle some links at present */
279 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
280 if (hb->dbuf.linkflag == 0) {
281 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
284 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
285 /* Do nothing here at the moment. do_tarput will handle this
286 as long as the longlink gets back to it, as it has to advance
287 the buffer pointer, etc */
289 DEBUG(0, ("this tar file appears to contain some kind \
290 of link other than a GNUtar Longlink - ignoring\n"));
296 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
297 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
300 finfo->mode=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
305 * Bug fix by richard@sj.co.uk
307 * REC: restore times correctly (as does tar)
308 * We only get the modification time of the file; set the creation time
309 * from the mod. time, and the access time to current time
311 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
312 finfo->atime = time(NULL);
313 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
318 /****************************************************************************
319 Write out the tar buffer to tape or wherever
320 ****************************************************************************/
322 static int dotarbuf(int f, char *b, int n)
329 /* This routine and the next one should be the only ones that do write()s */
330 if (tp + n >= tbufsiz) {
334 memcpy(tarbuf + tp, b, diff);
335 fail=fail && (1+write(f, tarbuf, tbufsiz));
340 while (n >= tbufsiz) {
341 fail=fail && (1 + write(f, b, tbufsiz));
348 memcpy(tarbuf+tp, b, n);
352 return(fail ? writ : 0);
355 /****************************************************************************
356 Write zeros to buffer / tape
357 ****************************************************************************/
359 static void dozerobuf(int f, int n)
361 /* short routine just to write out n zeros to buffer -
362 * used to round files to nearest block
363 * and to do tar EOFs */
368 if (n+tp >= tbufsiz) {
369 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
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=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 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
422 static void fixtarname(char *tptr, const char *fp, size_t l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
429 StrnCpy(tptr, fp, l-1);
430 string_replace(tptr, '\\', '/');
433 /****************************************************************************
434 Convert from decimal to octal string
435 ****************************************************************************/
437 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
439 /* Converts long to octal string, pads with leading zeros */
441 /* skip final null, but do final space */
445 /* Loop does at least one digit */
447 p[--ndgs] = '0' + (char) (value & 7);
449 } while (ndgs > 0 && value != 0);
451 /* Do leading zeros */
456 /****************************************************************************
457 Convert from octal string to long
458 ***************************************************************************/
460 static long unoct(char *p, int ndgs)
463 /* Converts octal string to long, ignoring any non-digit */
466 if (isdigit((int)*p))
467 value = (value << 3) | (long) (*p - '0');
475 /****************************************************************************
476 Compare two strings in a slash insensitive way, allowing s1 to match s2
477 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
478 a file in any subdirectory of s1, declare a match.
479 ***************************************************************************/
481 static int strslashcmp(char *s1, char *s2)
485 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
486 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
490 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
493 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
500 /* check for s1 is an "initial" string of s2 */
501 if ((*s2 == '/' || *s2 == '\\') && !*s1)
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
511 static BOOL ensurepath(char *fname)
513 /* *must* be called with buffer ready malloc'ed */
514 /* ensures path exists */
516 char *partpath, *ffname;
517 char *p=fname, *basehack;
519 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
521 partpath = string_create_s(strlen(fname));
522 ffname = string_create_s(strlen(fname));
524 if ((partpath == NULL) || (ffname == NULL)){
525 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
533 /* fname copied to ffname so can strtok */
535 safe_strcpy(ffname, fname, strlen(fname));
537 /* do a `basename' on ffname, so don't try and make file name directory */
538 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
543 p=strtok(ffname, "\\");
546 safe_strcat(partpath, p, strlen(fname) + 1);
548 if (!cli_chkpath(cli, partpath)) {
549 if (!cli_mkdir(cli, partpath)) {
550 DEBUG(0, ("Error mkdirhiering\n"));
553 DEBUG(3, ("mkdirhiering %s\n", partpath));
557 safe_strcat(partpath, "\\", strlen(fname) + 1);
558 p = strtok(NULL,"/\\");
564 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
569 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
570 memset(buf, 0, (size_t)bufsize);
571 while( !berr && padsize > 0 ) {
572 bytestowrite= (int)MIN(bufsize, padsize);
573 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
574 padsize -= bytestowrite;
580 static void do_setrattr(char *name, uint16 attr, int set)
584 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
586 if (set == ATTRSET) {
589 attr = oldattr & ~attr;
592 if (!cli_setatr(cli, name, attr, 0)) {
593 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
597 /****************************************************************************
598 append one remote file to the tar file
599 ***************************************************************************/
601 static void do_atar(char *rname,char *lname,file_info *finfo1)
604 SMB_BIG_UINT nread=0;
607 BOOL close_done = False;
608 BOOL shallitime=True;
610 int read_size = 65520;
613 struct timeval tp_start;
615 GetTimeOfDay(&tp_start);
617 ftype = '0'; /* An ordinary file ... */
620 finfo.size = finfo1 -> size;
621 finfo.mode = finfo1 -> mode;
622 finfo.uid = finfo1 -> uid;
623 finfo.gid = finfo1 -> gid;
624 finfo.mtime = finfo1 -> mtime;
625 finfo.atime = finfo1 -> atime;
626 finfo.ctime = finfo1 -> ctime;
627 finfo.name = finfo1 -> name;
629 finfo.size = def_finfo.size;
630 finfo.mode = def_finfo.mode;
631 finfo.uid = def_finfo.uid;
632 finfo.gid = def_finfo.gid;
633 finfo.mtime = def_finfo.mtime;
634 finfo.atime = def_finfo.atime;
635 finfo.ctime = def_finfo.ctime;
636 finfo.name = def_finfo.name;
640 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
641 (double)finfo.size));
643 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
648 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
650 dos_clean_name(rname);
653 DEBUG(0,("%s opening remote file %s (%s)\n",
654 cli_errstr(cli),rname, cur_dir));
658 finfo.name = string_create_s(strlen(rname));
659 if (finfo.name == NULL) {
660 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
664 safe_strcpy(finfo.name,rname, strlen(rname));
666 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
667 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
670 finfo.ctime = finfo.mtime;
673 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
675 if (tar_inc && !(finfo.mode & aARCH)) {
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
678 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
679 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
681 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
682 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
685 BOOL wrote_tar_header = False;
687 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
688 finfo.name, (double)finfo.size, lname));
690 while (nread < finfo.size && !close_done) {
692 DEBUG(3,("nread=%.0f\n",(double)nread));
694 datalen = cli_read(cli, fnum, data, nread, read_size);
697 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
703 /* Only if the first read succeeds, write out the tar header. */
704 if (!wrote_tar_header) {
705 /* write a tar header, don't bother with mode - just set to 100644 */
706 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
707 wrote_tar_header = True;
710 /* if file size has increased since we made file size query, truncate
711 read so tar header for this file will be correct.
714 if (nread > finfo.size) {
715 datalen -= nread - finfo.size;
716 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
717 finfo.name, (double)finfo.size));
720 /* add received bits of file to buffer - dotarbuf will
721 * write out in 512 byte intervals */
723 if (dotarbuf(tarhandle,data,datalen) != datalen) {
724 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
729 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
736 if (wrote_tar_header) {
737 /* pad tar file with zero's if we couldn't get entire file */
738 if (nread < finfo.size) {
739 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
740 (double)finfo.size, (int)nread));
741 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
742 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
745 /* round tar file to nearest block */
746 if (finfo.size % TBLOCK)
747 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
749 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
752 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
757 cli_close(cli, fnum);
760 struct timeval tp_end;
763 /* if shallitime is true then we didn't skip */
764 if (tar_reset && !dry_run)
765 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
767 GetTimeOfDay(&tp_end);
768 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
769 get_total_time_ms += this_time;
770 get_total_size += finfo.size;
773 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
774 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
778 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
779 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
780 finfo.size / MAX(0.001, (1.024*this_time)),
781 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
785 /****************************************************************************
786 Append single file to tar file (or not)
787 ***************************************************************************/
789 static void do_tar(file_info *finfo)
793 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
796 /* Is it on the exclude list ? */
797 if (!tar_excl && clipn) {
800 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
802 pstrcpy(exclaim, cur_dir);
803 *(exclaim+strlen(exclaim)-1)='\0';
805 pstrcat(exclaim, "\\");
806 pstrcat(exclaim, finfo->name);
808 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
810 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
811 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
812 DEBUG(3,("Skipping file %s\n", exclaim));
817 if (finfo->mode & aDIR) {
818 pstring saved_curdir;
821 pstrcpy(saved_curdir, cur_dir);
823 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
824 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
825 (int)sizeof(cur_dir), (int)strlen(cur_dir),
826 (int)strlen(finfo->name), finfo->name, cur_dir));
828 pstrcat(cur_dir,finfo->name);
829 pstrcat(cur_dir,"\\");
831 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
833 /* write a tar directory, don't bother with mode - just set it to
835 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
837 DEBUG(0,(" directory %s\n", cur_dir));
839 ntarf++; /* Make sure we have a file on there */
840 pstrcpy(mtar_mask,cur_dir);
841 pstrcat(mtar_mask,"*");
842 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
843 do_list(mtar_mask, attribute, do_tar, False, True);
844 pstrcpy(cur_dir,saved_curdir);
846 pstrcpy(rname,cur_dir);
847 pstrcat(rname,finfo->name);
848 do_atar(rname,finfo->name,finfo);
852 /****************************************************************************
853 Convert from UNIX to DOS file names
854 ***************************************************************************/
856 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
858 /* remove '.' from start of file name, convert from unix /'s to
859 * dos \'s in path. Kill any absolute path names. But only if first!
862 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
869 if (*fp == '\\' || *fp == '/') {
875 safe_strcpy(tptr, fp, l);
876 string_replace(tptr, '/', '\\');
879 /****************************************************************************
880 Move to the next block in the buffer, which may mean read in another set of
881 blocks. FIXME, we should allow more than one block to be skipped.
882 ****************************************************************************/
884 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
886 int bufread, total = 0;
888 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
892 if (*bufferp >= (ltarbuf + bufsiz)) {
894 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
897 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
898 * Fixes bug where read can return short if coming from
902 bufread = read(tarhandle, ltarbuf, bufsiz);
905 while (total < bufsiz) {
906 if (bufread < 0) { /* An error, return false */
907 return (total > 0 ? -2 : bufread);
915 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
919 DEBUG(5, ("Total bytes read ... %i\n", total));
927 /* Skip a file, even if it includes a long file name? */
928 static int skip_file(int skipsize)
930 int dsize = skipsize;
932 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
934 /* FIXME, we should skip more than one block at a time */
937 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
938 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
947 /*************************************************************
948 Get a file from the tar file and store it.
949 When this is called, tarbuf already contains the first
950 file block. This is a bit broken & needs fixing.
951 **************************************************************/
953 static int get_file(file_info2 finfo)
955 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
956 SMB_BIG_UINT rsize = 0;
958 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
960 if (ensurepath(finfo.name) &&
961 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
962 DEBUG(0, ("abandoning restore\n"));
966 /* read the blocks from the tar file and write to the remote file */
968 rsize = finfo.size; /* This is how much to write */
972 /* We can only write up to the end of the buffer */
973 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
974 dsize = MIN(dsize, rsize); /* Should be only what is left */
975 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
977 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
978 DEBUG(0, ("Error writing remote file\n"));
985 /* Now figure out how much to move in the buffer */
987 /* FIXME, we should skip more than one block at a time */
989 /* First, skip any initial part of the part written that is left over */
990 /* from the end of the first TBLOCK */
992 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
993 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
996 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
997 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1003 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1004 * If the file being extracted is an exact multiple of
1005 * TBLOCK bytes then we don't want to extract the next
1006 * block from the tarfile here, as it will be done in
1007 * the caller of get_file().
1010 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1011 ((rsize == 0) && (dsize > TBLOCK))) {
1013 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1014 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1023 /* Now close the file ... */
1025 if (!cli_close(cli, fnum)) {
1026 DEBUG(0, ("Error closing remote file\n"));
1030 /* Now we update the creation date ... */
1031 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1033 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1034 if (tar_real_noisy) {
1035 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1036 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1041 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1045 /* Create a directory. We just ensure that the path exists and return as there
1046 is no file associated with a directory
1048 static int get_dir(file_info2 finfo)
1050 DEBUG(0, ("restore directory %s\n", finfo.name));
1052 if (!ensurepath(finfo.name)) {
1053 DEBUG(0, ("Problems creating directory\n"));
1060 /* Get a file with a long file name ... first file has file name, next file
1061 has the data. We only want the long file name, as the loop in do_tarput
1062 will deal with the rest.
1064 static char *get_longfilename(file_info2 finfo)
1066 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1068 int namesize = finfo.size + strlen(cur_dir) + 2;
1069 char *longname = SMB_MALLOC(namesize);
1070 int offset = 0, left = finfo.size;
1073 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1074 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1076 if (longname == NULL) {
1077 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1081 /* First, add cur_dir to the long file name */
1083 if (strlen(cur_dir) > 0) {
1084 strncpy(longname, cur_dir, namesize);
1085 offset = strlen(cur_dir);
1088 /* Loop through the blocks picking up the name */
1091 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1092 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1093 SAFE_FREE(longname);
1097 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1098 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1107 static void do_tarput(void)
1110 struct timeval tp_start;
1111 char *longfilename = NULL, linkflag;
1116 GetTimeOfDay(&tp_start);
1117 DEBUG(5, ("RJS do_tarput called ...\n"));
1119 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1121 /* Now read through those files ... */
1123 /* Get us to the next block, or the first block first time around */
1124 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1125 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1126 SAFE_FREE(longfilename);
1130 DEBUG(5, ("Reading the next header ...\n"));
1132 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1133 case -2: /* Hmm, not good, but not fatal */
1134 DEBUG(0, ("Skipping %s...\n", finfo.name));
1135 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1136 DEBUG(0, ("Short file, bailing out...\n"));
1142 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1145 case 0: /* chksum is zero - looks like an EOF */
1146 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1147 return; /* Hmmm, bad here ... */
1154 /* Now, do we have a long file name? */
1155 if (longfilename != NULL) {
1156 SAFE_FREE(finfo.name); /* Free the space already allocated */
1157 finfo.name = longfilename;
1158 longfilename = NULL;
1161 /* Well, now we have a header, process the file ... */
1162 /* Should we skip the file? We have the long name as well here */
1163 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1164 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1166 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1168 skip_file(finfo.size);
1172 /* We only get this far if we should process the file */
1173 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1175 case '0': /* Should use symbolic names--FIXME */
1177 * Skip to the next block first, so we can get the file, FIXME, should
1178 * be in get_file ...
1179 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1180 * Fixes bug where file size in tarfile is zero.
1182 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1183 DEBUG(0, ("Short file, bailing out...\n"));
1186 if (!get_file(finfo)) {
1187 DEBUG(0, ("Abandoning restore\n"));
1192 if (!get_dir(finfo)) {
1193 DEBUG(0, ("Abandoning restore \n"));
1198 SAFE_FREE(longfilename);
1199 longfilename = get_longfilename(finfo);
1200 if (!longfilename) {
1201 DEBUG(0, ("abandoning restore\n"));
1204 DEBUG(5, ("Long file name: %s\n", longfilename));
1208 skip_file(finfo.size); /* Don't handle these yet */
1215 * samba interactive commands
1218 /****************************************************************************
1220 ***************************************************************************/
1227 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1228 DEBUG(0, ("blocksize <n>\n"));
1233 if (block < 0 || block > 65535) {
1234 DEBUG(0, ("blocksize out of range"));
1239 DEBUG(2,("blocksize is now %d\n", blocksize));
1244 /****************************************************************************
1245 command to set incremental / reset mode
1246 ***************************************************************************/
1248 int cmd_tarmode(void)
1252 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1253 if (strequal(buf, "full"))
1255 else if (strequal(buf, "inc"))
1257 else if (strequal(buf, "reset"))
1259 else if (strequal(buf, "noreset"))
1261 else if (strequal(buf, "system"))
1263 else if (strequal(buf, "nosystem"))
1265 else if (strequal(buf, "hidden"))
1267 else if (strequal(buf, "nohidden"))
1269 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1271 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1274 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1277 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1278 tar_inc ? "incremental" : "full",
1279 tar_system ? "system" : "nosystem",
1280 tar_hidden ? "hidden" : "nohidden",
1281 tar_reset ? "reset" : "noreset",
1282 tar_noisy ? "verbose" : "quiet"));
1286 /****************************************************************************
1287 Feeble attrib command
1288 ***************************************************************************/
1290 int cmd_setmode(void)
1298 attra[0] = attra[1] = 0;
1300 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1301 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1305 pstrcpy(fname, cur_dir);
1306 pstrcat(fname, buf);
1308 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1320 attra[direct]|=aRONLY;
1323 attra[direct]|=aHIDDEN;
1326 attra[direct]|=aSYSTEM;
1329 attra[direct]|=aARCH;
1332 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1338 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1339 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1343 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1344 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1345 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1349 /****************************************************************************
1350 Principal command for creating / extracting
1351 ***************************************************************************/
1360 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1361 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1365 argl=toktocliplist(&argcl, NULL);
1366 if (!tar_parseargs(argcl, argl, buf, 0))
1369 ret = process_tar();
1374 /****************************************************************************
1375 Command line (option) version
1376 ***************************************************************************/
1378 int process_tar(void)
1395 if (clipn && tar_excl) {
1399 for (i=0; i<clipn; i++) {
1400 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1402 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1403 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1406 if (strrchr_m(cliplist[i], '\\')) {
1409 pstrcpy(saved_dir, cur_dir);
1411 if (*cliplist[i]=='\\') {
1412 pstrcpy(tarmac, cliplist[i]);
1414 pstrcpy(tarmac, cur_dir);
1415 pstrcat(tarmac, cliplist[i]);
1417 pstrcpy(cur_dir, tarmac);
1418 *(strrchr_m(cur_dir, '\\')+1)='\0';
1420 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1421 do_list(tarmac,attribute,do_tar, False, True);
1422 pstrcpy(cur_dir,saved_dir);
1424 pstrcpy(tarmac, cur_dir);
1425 pstrcat(tarmac, cliplist[i]);
1426 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1427 do_list(tarmac,attribute,do_tar, False, True);
1432 pstrcpy(mask,cur_dir);
1433 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1434 pstrcat(mask,"\\*");
1435 do_list(mask,attribute,do_tar,False, True);
1439 dotareof(tarhandle);
1443 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1444 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1448 if (must_free_cliplist) {
1450 for (i = 0; i < clipn; ++i) {
1451 SAFE_FREE(cliplist[i]);
1453 SAFE_FREE(cliplist);
1456 must_free_cliplist = False;
1461 /****************************************************************************
1462 Find a token (filename) in a clip list
1463 ***************************************************************************/
1465 static int clipfind(char **aret, int ret, char *tok)
1470 /* ignore leading slashes or dots in token */
1471 while(strchr_m("/\\.", *tok))
1477 /* ignore leading slashes or dots in list */
1478 while(strchr_m("/\\.", *pkey))
1481 if (!strslashcmp(pkey, tok))
1487 /****************************************************************************
1488 Read list of files to include from the file and initialize cliplist
1490 ***************************************************************************/
1492 static int read_inclusion_file(char *filename)
1494 XFILE *inclusion = NULL;
1495 char buf[PATH_MAX + 1];
1496 char *inclusion_buffer = NULL;
1497 int inclusion_buffer_size = 0;
1498 int inclusion_buffer_sofar = 0;
1505 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1506 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1507 /* XXX It would be better to include a reason for failure, but without
1508 * autoconf, it's hard to use strerror, sys_errlist, etc.
1510 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1514 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1515 if (inclusion_buffer == NULL) {
1516 inclusion_buffer_size = 1024;
1517 if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1518 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1524 if (buf[strlen(buf)-1] == '\n') {
1525 buf[strlen(buf)-1] = '\0';
1528 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1529 inclusion_buffer_size *= 2;
1530 inclusion_buffer = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1531 if (!inclusion_buffer) {
1532 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1533 inclusion_buffer_size));
1539 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1540 inclusion_buffer_sofar += strlen(buf) + 1;
1543 x_fclose(inclusion);
1546 /* Allocate an array of clipn + 1 char*'s for cliplist */
1547 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1548 if (cliplist == NULL) {
1549 DEBUG(0,("failure allocating memory for cliplist\n"));
1552 cliplist[clipn] = NULL;
1553 p = inclusion_buffer;
1554 for (i = 0; (! error) && (i < clipn); i++) {
1555 /* set current item to NULL so array will be null-terminated even if
1556 * malloc fails below. */
1558 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1559 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1562 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1563 cliplist[i] = tmpstr;
1564 if ((p = strchr_m(p, '\000')) == NULL) {
1565 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1571 must_free_cliplist = True;
1575 SAFE_FREE(inclusion_buffer);
1579 /* We know cliplist is always null-terminated */
1580 for (pp = cliplist; *pp; ++pp) {
1583 SAFE_FREE(cliplist);
1585 must_free_cliplist = False;
1590 /* cliplist and its elements are freed at the end of process_tar. */
1594 /****************************************************************************
1595 Parse tar arguments. Sets tar_type, tar_excl, etc.
1596 ***************************************************************************/
1598 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1600 int newOptind = Optind;
1601 char tar_clipfl='\0';
1603 /* Reset back to defaults - could be from interactive version
1604 * reset mode and archive mode left as they are though
1616 if (tar_type=='c') {
1617 printf("Tar must be followed by only one of c or x.\n");
1623 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1624 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1636 DEBUG(0,("Option N must be followed by valid file name\n"));
1639 SMB_STRUCT_STAT stbuf;
1641 if (sys_stat(argv[Optind], &stbuf) == 0) {
1642 newer_than = stbuf.st_mtime;
1643 DEBUG(1,("Getting files newer than %s",
1644 asctime(localtime(&newer_than))));
1648 DEBUG(0,("Error setting newer-than time\n"));
1661 DEBUG(0,("Only one of I,X,F must be specified\n"));
1668 DEBUG(0,("Only one of I,X,F must be specified\n"));
1675 DEBUG(0,("Only one of I,X,F must be specified\n"));
1681 DEBUG(0, ("tar_re_search set\n"));
1682 tar_re_search = True;
1685 if (tar_type == 'c') {
1686 DEBUG(0, ("dry_run set\n"));
1689 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1694 DEBUG(0,("Unknown tar option\n"));
1700 printf("Option T must be followed by one of c or x.\n");
1704 /* tar_excl is true if cliplist lists files to be included.
1705 * Both 'I' and 'F' mean include. */
1706 tar_excl=tar_clipfl!='X';
1708 if (tar_clipfl=='F') {
1709 if (argc-Optind-1 != 1) {
1710 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1714 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1715 if (! read_inclusion_file(argv[Optind+1])) {
1718 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1723 cliplist=argv+Optind+1;
1724 clipn=argc-Optind-1;
1727 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1728 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1732 for (clipcount = 0; clipcount < clipn; clipcount++) {
1734 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1736 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1737 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1742 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1743 tmplist[clipcount] = tmpstr;
1744 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1746 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1750 must_free_cliplist = True;
1755 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1756 /* Doing regular expression seaches not from an inclusion file. */
1757 clipn=argc-Optind-1;
1758 cliplist=argv+Optind+1;
1762 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1763 /* Sets tar handle to either 0 or 1, as appropriate */
1764 tarhandle=(tar_type=='c');
1766 * Make sure that dbf points to stderr if we are using stdout for
1769 if (tarhandle == 1) {
1772 if (!argv[Optind]) {
1773 DEBUG(0,("Must specify tar filename\n"));
1776 if (!strcmp(argv[Optind], "-")) {
1781 if (tar_type=='c' && dry_run) {
1783 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1784 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1785 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));