2 Unix SMB/Netbios implementation.
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct
52 /* These times are normally kept in GMT */
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
71 #define SEPARATORS " \t\n\r"
72 extern int DEBUGLEVEL;
73 extern struct cli_state *cli;
76 /* These defines are for the do_setrattr routine, to indicate
77 * setting and reseting of file attributes in the function call */
81 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
83 #ifndef CLIENT_TIMEOUT
84 #define CLIENT_TIMEOUT (30*1000)
87 static char *tarbuf, *buffer_p;
88 static int tp, ntarf, tbufsiz;
90 /* Incremental mode */
92 /* Reset archive bit */
94 /* Include / exclude mode (true=include, false=exclude) */
96 /* use regular expressions for search on file names */
97 BOOL tar_re_search=False;
101 /* Do not dump anything, just calculate sizes */
103 /* Dump files with System attribute */
104 BOOL tar_system=True;
105 /* Dump files with Hidden attribute */
106 BOOL tar_hidden=True;
107 /* Be noisy - make a catalogue */
109 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
112 static char **cliplist=NULL;
114 static BOOL must_free_cliplist = False;
116 extern file_info def_finfo;
117 extern BOOL lowercase;
119 extern BOOL readbraw_supported;
121 extern pstring cur_dir;
122 extern int get_total_time_ms;
123 extern int get_total_size;
128 static void writetarheader(int f, char *aname, int size, time_t mtime,
129 char *amode, unsigned char ftype);
130 static void do_atar(char *rname,char *lname,file_info *finfo1);
131 static void do_tar(file_info *finfo);
132 static void oct_it(long value, int ndgs, char *p);
133 static void fixtarname(char *tptr, char *fp, int l);
134 static int dotarbuf(int f, char *b, int n);
135 static void dozerobuf(int f, int n);
136 static void dotareof(int f);
137 static void initarbuf(void);
139 /* restore functions */
140 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
141 static long unoct(char *p, int ndgs);
142 static void do_tarput(void);
143 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
146 * tar specific utitlities
149 /*******************************************************************
150 Create a string of size size+1 (for the null)
151 *******************************************************************/
152 static char *string_create_s(int size)
156 tmp = (char *)malloc(size+1);
160 DEBUG(0, ("Out of memory in string_create_s\n"));
168 /****************************************************************************
169 Write a tar header to buffer
170 ****************************************************************************/
171 static void writetarheader(int f, char *aname, int size, time_t mtime,
172 char *amode, unsigned char ftype)
178 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
180 memset(hb.dummy, 0, sizeof(hb.dummy));
183 if (l >= NAMSIZ - 1) {
184 /* write a GNU tar style long header */
186 b = (char *)malloc(l+TBLOCK+100);
188 DEBUG(0,("out of memory\n"));
191 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
192 memset(b, 0, l+TBLOCK+100);
193 fixtarname(b, aname, l);
195 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
196 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
200 /* use l + 1 to do the null too */
201 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
204 strlower(hb.dbuf.name);
206 /* write out a "standard" tar format header */
208 hb.dbuf.name[NAMSIZ-1]='\0';
209 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
210 oct_it(0L, 8, hb.dbuf.uid);
211 oct_it(0L, 8, hb.dbuf.gid);
212 oct_it((long) size, 13, hb.dbuf.size);
213 oct_it((long) mtime, 13, hb.dbuf.mtime);
214 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
215 memset(hb.dbuf.linkname, 0, NAMSIZ);
216 hb.dbuf.linkflag=ftype;
218 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
220 oct_it((long) chk, 8, hb.dbuf.chksum);
221 hb.dbuf.chksum[6] = '\0';
223 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
226 /****************************************************************************
227 Read a tar header into a hblock structure, and validate
228 ***************************************************************************/
229 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
236 * read in a "standard" tar format header - we're not that interested
237 * in that many fields, though
240 /* check the checksum */
241 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
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));
259 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
260 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
264 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
266 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
271 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
273 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
274 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
275 strlen(hb->dbuf.name) + 1, True);
277 /* can't handle some links at present */
278 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
279 if (hb->dbuf.linkflag == 0) {
280 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
283 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
284 /* Do nothing here at the moment. do_tarput will handle this
285 as long as the longlink gets back to it, as it has to advance
286 the buffer pointer, etc */
289 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
295 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
296 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
301 finfo->mode=0; /* we don't care about mode at the moment, we'll
302 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
306 * REC: restore times correctly (as does tar)
307 * We only get the modification time of the file; set the creation time
308 * from the mod. time, and the access time to current time
310 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
311 finfo->atime = time(NULL);
312 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
320 static int dotarbuf(int f, char *b, int n)
327 /* This routine and the next one should be the only ones that do write()s */
328 if (tp + n >= tbufsiz)
333 memcpy(tarbuf + tp, b, diff);
334 fail=fail && (1+write(f, tarbuf, tbufsiz));
341 fail=fail && (1 + write(f, b, tbufsiz));
347 memcpy(tarbuf+tp, b, n);
351 return(fail ? writ : 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
357 static void dozerobuf(int f, int n)
359 /* short routine just to write out n zeros to buffer -
360 * used to round files to nearest block
361 * and to do tar EOFs */
368 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
375 memset(tarbuf+tp, 0, n);
380 /****************************************************************************
382 ****************************************************************************/
383 static void initarbuf(void)
385 /* initialize tar buffer */
386 tbufsiz=blocksize*TBLOCK;
387 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
389 /* reset tar buffer pointer and tar file counter and total dumped */
390 tp=0; ntarf=0; ttarf=0;
393 /****************************************************************************
394 Write two zero blocks at end of file
395 ****************************************************************************/
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)
409 DEBUG(0, ("Couldn't stat file handle\n"));
413 /* Could be a pipe, in which case S_ISREG should fail,
414 * and we should write out at full size */
415 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
421 static void fixtarname(char *tptr, char *fp, int l)
423 /* add a '.' to start of file name, convert from ugly dos \'s in path
424 * to lovely unix /'s :-} */
427 safe_strcpy(tptr, fp, l);
428 string_replace(tptr, '\\', '/');
431 /****************************************************************************
432 Convert from decimal to octal string
433 ****************************************************************************/
434 static void oct_it (long value, int ndgs, char *p)
436 /* Converts long to octal string, pads with leading zeros */
438 /* skip final null, but do final space */
442 /* Loop does at least one digit */
444 p[--ndgs] = '0' + (char) (value & 7);
447 while (ndgs > 0 && value != 0);
449 /* Do leading zeros */
454 /****************************************************************************
455 Convert from octal string to long
456 ***************************************************************************/
457 static long unoct(char *p, int ndgs)
460 /* Converts octal string to long, ignoring any non-digit */
464 if (isdigit((int)*p))
465 value = (value << 3) | (long) (*p - '0');
473 /****************************************************************************
474 Compare two strings in a slash insensitive way, allowing s1 to match s2
475 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
476 a file in any subdirectory of s1, declare a match.
477 ***************************************************************************/
478 static int strslashcmp(char *s1, char *s2)
484 || tolower(*s1) == tolower(*s2)
485 || (*s1 == '\\' && *s2=='/')
486 || (*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) == '\\')) return 0;
495 /* ignore trailing slash on s1 */
496 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
498 /* check for s1 is an "initial" string of s2 */
499 if (*s2 == '/' || *s2 == '\\') return 0;
505 /****************************************************************************
506 Ensure a remote path exists (make if necessary)
507 ***************************************************************************/
508 static BOOL ensurepath(char *fname)
510 /* *must* be called with buffer ready malloc'ed */
511 /* ensures path exists */
513 char *partpath, *ffname;
514 char *p=fname, *basehack;
516 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
518 partpath = string_create_s(strlen(fname));
519 ffname = string_create_s(strlen(fname));
521 if ((partpath == NULL) || (ffname == NULL)){
523 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
530 /* fname copied to ffname so can strtok */
532 safe_strcpy(ffname, fname, strlen(fname));
534 /* do a `basename' on ffname, so don't try and make file name directory */
535 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
540 p=strtok(ffname, "\\");
544 safe_strcat(partpath, p, strlen(fname) + 1);
546 if (!cli_chkpath(cli, partpath)) {
547 if (!cli_mkdir(cli, partpath))
549 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, int bufsize, int padsize)
569 DEBUG(5, ("Padding with %d zeros\n", padsize));
570 memset(buf, 0, bufsize);
571 while( !berr && padsize > 0 ) {
572 bytestowrite= MIN(bufsize, padsize);
573 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
574 padsize -= bytestowrite;
581 static void do_setrattr(char *name, uint16 attr, int set)
585 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
587 if (set == ATTRSET) {
590 attr = oldattr & ~attr;
593 if (!cli_setatr(cli, name, attr, 0)) {
594 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
599 /****************************************************************************
600 append one remote file to the tar file
601 ***************************************************************************/
602 static void do_atar(char *rname,char *lname,file_info *finfo1)
608 BOOL close_done = False;
609 BOOL shallitime=True;
611 int read_size = 65520;
614 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;
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;
640 DEBUG(3,("skipping file %s of size %d bytes\n",
644 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
649 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
651 dos_clean_name(rname);
654 DEBUG(0,("%s opening remote file %s (%s)\n",
655 cli_errstr(cli),rname, cur_dir));
659 finfo.name = string_create_s(strlen(rname));
660 if (finfo.name == NULL) {
661 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
665 safe_strcpy(finfo.name,rname, strlen(rname));
667 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
668 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
671 finfo.ctime = finfo.mtime;
674 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
676 if (tar_inc && !(finfo.mode & aARCH))
678 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
681 else if (!tar_system && (finfo.mode & aSYSTEM))
683 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
686 else if (!tar_hidden && (finfo.mode & aHIDDEN))
688 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
693 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
698 /* write a tar header, don't bother with mode - just set to 100644 */
699 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
701 while (nread < finfo.size && !close_done) {
703 DEBUG(3,("nread=%d\n",nread));
705 datalen = cli_read(cli, fnum, data, nread, read_size);
708 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
714 /* if file size has increased since we made file size query, truncate
715 read so tar header for this file will be correct.
718 if (nread > finfo.size) {
719 datalen -= nread - finfo.size;
720 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
723 /* add received bits of file to buffer - dotarbuf will
724 * write out in 512 byte intervals */
725 if (dotarbuf(tarhandle,data,datalen) != datalen) {
726 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
731 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
738 /* pad tar file with zero's if we couldn't get entire file */
739 if (nread < finfo.size) {
740 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
741 if (padit(data, 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);
753 cli_close(cli, fnum);
757 struct timeval tp_end;
760 /* if shallitime is true then we didn't skip */
761 if (tar_reset && !dry_run)
762 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
764 GetTimeOfDay(&tp_end);
766 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
767 (tp_end.tv_usec - tp_start.tv_usec)/1000;
768 get_total_time_ms += this_time;
769 get_total_size += finfo.size;
773 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
774 (int)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 ***************************************************************************/
788 static void do_tar(file_info *finfo)
792 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
795 /* Is it on the exclude list ? */
796 if (!tar_excl && clipn) {
799 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
801 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
802 *(exclaim+strlen(exclaim)-1)='\0';
804 safe_strcat(exclaim, "\\", sizeof(pstring));
805 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
807 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
809 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
811 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
813 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
815 DEBUG(3,("Skipping file %s\n", exclaim));
820 if (finfo->mode & aDIR)
822 pstring saved_curdir;
825 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
827 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
829 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
830 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
832 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
834 /* write a tar directory, don't bother with mode - just set it to
836 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
838 DEBUG(0,(" directory %s\n", cur_dir));
840 ntarf++; /* Make sure we have a file on there */
841 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
842 safe_strcat(mtar_mask,"*", sizeof(pstring));
843 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
844 do_list(mtar_mask, attribute, do_tar, False, True);
845 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
849 safe_strcpy(rname,cur_dir, sizeof(pstring));
850 safe_strcat(rname,finfo->name, sizeof(pstring));
851 do_atar(rname,finfo->name,finfo);
855 /****************************************************************************
856 Convert from UNIX to DOS file names
857 ***************************************************************************/
858 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
860 /* remove '.' from start of file name, convert from unix /'s to
861 * dos \'s in path. Kill any absolute path names. But only if first!
864 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
871 if (*fp == '\\' || *fp == '/') {
877 safe_strcpy(tptr, fp, l);
878 string_replace(tptr, '/', '\\');
882 /****************************************************************************
883 Move to the next block in the buffer, which may mean read in another set of
884 blocks. FIXME, we should allow more than one block to be skipped.
885 ****************************************************************************/
886 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
888 int bufread, total = 0;
890 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
894 if (*bufferp >= (ltarbuf + bufsiz)) {
896 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
899 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
900 * Fixes bug where read can return short if coming from
904 bufread = read(tarhandle, ltarbuf, bufsiz);
907 while (total < bufsiz) {
908 if (bufread < 0) { /* An error, return false */
909 return (total > 0 ? -2 : bufread);
917 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
921 DEBUG(5, ("Total bytes read ... %i\n", total));
931 /* Skip a file, even if it includes a long file name? */
932 static int skip_file(int skipsize)
934 int dsize = skipsize;
936 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
938 /* FIXME, we should skip more than one block at a time */
942 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
944 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, rsize = 0, bpos = 0;
966 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
968 if (ensurepath(finfo.name) &&
969 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
970 DEBUG(0, ("abandoning restore\n"));
974 /* read the blocks from the tar file and write to the remote file */
976 rsize = finfo.size; /* This is how much to write */
980 /* 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)) {
1003 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1006 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1007 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1015 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1016 * If the file being extracted is an exact multiple of
1017 * TBLOCK bytes then we don't want to extract the next
1018 * block from the tarfile here, as it will be done in
1019 * the caller of get_file().
1022 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1023 ((rsize == 0) && (dsize > TBLOCK))) {
1025 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1026 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1037 /* Now close the file ... */
1039 if (!cli_close(cli, fnum)) {
1040 DEBUG(0, ("Error closing remote file\n"));
1044 /* Now we update the creation date ... */
1046 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1048 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1049 if (tar_real_noisy) {
1050 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1051 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1057 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1062 /* Create a directory. We just ensure that the path exists and return as there
1063 is no file associated with a directory
1065 static int get_dir(file_info2 finfo)
1068 DEBUG(0, ("restore directory %s\n", finfo.name));
1070 if (!ensurepath(finfo.name)) {
1072 DEBUG(0, ("Problems creating directory\n"));
1081 /* Get a file with a long file name ... first file has file name, next file
1082 has the data. We only want the long file name, as the loop in do_tarput
1083 will deal with the rest.
1085 static char * get_longfilename(file_info2 finfo)
1087 int namesize = finfo.size + strlen(cur_dir) + 2;
1088 char *longname = malloc(namesize);
1089 int offset = 0, left = finfo.size;
1092 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1093 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1095 if (longname == NULL) {
1097 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1098 (int)(finfo.size + strlen(cur_dir) + 2)));
1102 /* First, add cur_dir to the long file name */
1104 if (strlen(cur_dir) > 0) {
1105 strncpy(longname, cur_dir, namesize);
1106 offset = strlen(cur_dir);
1109 /* Loop through the blocks picking up the name */
1113 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1115 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1120 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1121 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1132 static void do_tarput(void)
1135 struct timeval tp_start;
1136 char *longfilename = NULL, linkflag;
1139 GetTimeOfDay(&tp_start);
1141 DEBUG(5, ("RJS do_tarput called ...\n"));
1143 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1145 /* Now read through those files ... */
1149 /* Get us to the next block, or the first block first time around */
1151 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1153 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1159 DEBUG(5, ("Reading the next header ...\n"));
1161 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1163 case -2: /* Hmm, not good, but not fatal */
1164 DEBUG(0, ("Skipping %s...\n", finfo.name));
1165 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1166 !skip_file(finfo.size)) {
1168 DEBUG(0, ("Short file, bailing out...\n"));
1176 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1179 case 0: /* chksum is zero - looks like an EOF */
1180 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1181 return; /* Hmmm, bad here ... */
1190 /* Now, do we have a long file name? */
1192 if (longfilename != NULL) {
1194 free(finfo.name); /* Free the space already allocated */
1195 finfo.name = longfilename;
1196 longfilename = NULL;
1200 /* Well, now we have a header, process the file ... */
1202 /* Should we skip the file? We have the long name as well here */
1205 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1207 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1209 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1212 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1216 skip_file(finfo.size);
1221 /* We only get this far if we should process the file */
1222 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1226 case '0': /* Should use symbolic names--FIXME */
1229 * Skip to the next block first, so we can get the file, FIXME, should
1230 * be in get_file ...
1231 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1232 * Fixes bug where file size in tarfile is zero.
1235 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1236 DEBUG(0, ("Short file, bailing out...\n"));
1239 if (!get_file(finfo)) {
1240 DEBUG(0, ("Abandoning restore\n"));
1247 if (!get_dir(finfo)) {
1248 DEBUG(0, ("Abandoning restore \n"));
1254 longfilename = get_longfilename(finfo);
1255 if (!longfilename) {
1256 DEBUG(0, ("abandoning restore\n"));
1260 DEBUG(5, ("Long file name: %s\n", longfilename));
1264 skip_file(finfo.size); /* Don't handle these yet */
1276 * samba interactive commands
1279 /****************************************************************************
1281 ***************************************************************************/
1282 void cmd_block(void)
1287 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1289 DEBUG(0, ("blocksize <n>\n"));
1294 if (block < 0 || block > 65535)
1296 DEBUG(0, ("blocksize out of range"));
1301 DEBUG(2,("blocksize is now %d\n", blocksize));
1304 /****************************************************************************
1305 command to set incremental / reset mode
1306 ***************************************************************************/
1307 void cmd_tarmode(void)
1311 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1312 if (strequal(buf, "full"))
1314 else if (strequal(buf, "inc"))
1316 else if (strequal(buf, "reset"))
1318 else if (strequal(buf, "noreset"))
1320 else if (strequal(buf, "system"))
1322 else if (strequal(buf, "nosystem"))
1324 else if (strequal(buf, "hidden"))
1326 else if (strequal(buf, "nohidden"))
1328 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1330 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1332 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1335 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1336 tar_inc ? "incremental" : "full",
1337 tar_system ? "system" : "nosystem",
1338 tar_hidden ? "hidden" : "nohidden",
1339 tar_reset ? "reset" : "noreset",
1340 tar_noisy ? "verbose" : "quiet"));
1344 /****************************************************************************
1345 Feeble attrib command
1346 ***************************************************************************/
1347 void cmd_setmode(void)
1355 attra[0] = attra[1] = 0;
1357 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1359 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1363 safe_strcpy(fname, cur_dir, sizeof(pstring));
1364 safe_strcat(fname, buf, sizeof(pstring));
1366 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1375 case 'r': attra[direct]|=aRONLY;
1377 case 'h': attra[direct]|=aHIDDEN;
1379 case 's': attra[direct]|=aSYSTEM;
1381 case 'a': attra[direct]|=aARCH;
1383 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1388 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1390 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1394 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1395 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1396 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1399 /****************************************************************************
1400 Principal command for creating / extracting
1401 ***************************************************************************/
1408 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1410 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1414 argl=toktocliplist(&argcl, NULL);
1415 if (!tar_parseargs(argcl, argl, buf, 0))
1423 /****************************************************************************
1424 Command line (option) version
1425 ***************************************************************************/
1426 int process_tar(void)
1442 if (clipn && tar_excl) {
1446 for (i=0; i<clipn; i++) {
1447 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1449 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1450 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1453 if (strrchr_m(cliplist[i], '\\')) {
1456 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1458 if (*cliplist[i]=='\\') {
1459 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1461 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1462 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1464 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1465 *(strrchr_m(cur_dir, '\\')+1)='\0';
1467 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1468 do_list(tarmac,attribute,do_tar, False, True);
1469 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1471 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1472 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1473 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1474 do_list(tarmac,attribute,do_tar, False, True);
1479 safe_strcpy(mask,cur_dir, sizeof(pstring));
1480 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1481 safe_strcat(mask,"\\*", sizeof(pstring));
1482 do_list(mask,attribute,do_tar,False, True);
1485 if (ntarf) dotareof(tarhandle);
1489 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1490 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1494 if (must_free_cliplist) {
1496 for (i = 0; i < clipn; ++i) {
1502 must_free_cliplist = False;
1508 /****************************************************************************
1509 Find a token (filename) in a clip list
1510 ***************************************************************************/
1511 static int clipfind(char **aret, int ret, char *tok)
1513 if (aret==NULL) return 0;
1515 /* ignore leading slashes or dots in token */
1516 while(strchr_m("/\\.", *tok)) tok++;
1521 /* ignore leading slashes or dots in list */
1522 while(strchr_m("/\\.", *pkey)) pkey++;
1524 if (!strslashcmp(pkey, tok)) return 1;
1530 /****************************************************************************
1531 Read list of files to include from the file and initialize cliplist
1533 ***************************************************************************/
1534 static int read_inclusion_file(char *filename)
1536 XFILE *inclusion = NULL;
1537 char buf[MAXPATHLEN + 1];
1538 char *inclusion_buffer = NULL;
1539 int inclusion_buffer_size = 0;
1540 int inclusion_buffer_sofar = 0;
1547 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1548 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1549 /* XXX It would be better to include a reason for failure, but without
1550 * autoconf, it's hard to use strerror, sys_errlist, etc.
1552 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1556 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1557 if (inclusion_buffer == NULL) {
1558 inclusion_buffer_size = 1024;
1559 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1560 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1566 if (buf[strlen(buf)-1] == '\n') {
1567 buf[strlen(buf)-1] = '\0';
1570 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1572 inclusion_buffer_size *= 2;
1573 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1575 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1576 inclusion_buffer_size));
1580 else inclusion_buffer = ib;
1583 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1584 inclusion_buffer_sofar += strlen(buf) + 1;
1587 x_fclose(inclusion);
1590 /* Allocate an array of clipn + 1 char*'s for cliplist */
1591 cliplist = malloc((clipn + 1) * sizeof(char *));
1592 if (cliplist == NULL) {
1593 DEBUG(0,("failure allocating memory for cliplist\n"));
1596 cliplist[clipn] = NULL;
1597 p = inclusion_buffer;
1598 for (i = 0; (! error) && (i < clipn); i++) {
1599 /* set current item to NULL so array will be null-terminated even if
1600 * malloc fails below. */
1602 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1603 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1606 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1607 cliplist[i] = tmpstr;
1608 if ((p = strchr_m(p, '\000')) == NULL) {
1609 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1615 must_free_cliplist = True;
1619 if (inclusion_buffer) {
1620 free(inclusion_buffer);
1625 /* We know cliplist is always null-terminated */
1626 for (pp = cliplist; *pp; ++pp) {
1631 must_free_cliplist = False;
1636 /* cliplist and its elements are freed at the end of process_tar. */
1640 /****************************************************************************
1641 Parse tar arguments. Sets tar_type, tar_excl, etc.
1642 ***************************************************************************/
1643 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1645 char tar_clipfl='\0';
1647 /* Reset back to defaults - could be from interactive version
1648 * reset mode and archive mode left as they are though
1660 if (tar_type=='c') {
1661 printf("Tar must be followed by only one of c or x.\n");
1667 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1668 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1679 DEBUG(0,("Option N must be followed by valid file name\n"));
1682 SMB_STRUCT_STAT stbuf;
1683 extern time_t newer_than;
1685 if (sys_stat(argv[Optind], &stbuf) == 0) {
1686 newer_than = stbuf.st_mtime;
1687 DEBUG(1,("Getting files newer than %s",
1688 asctime(LocalTime(&newer_than))));
1691 DEBUG(0,("Error setting newer-than time\n"));
1704 DEBUG(0,("Only one of I,X,F must be specified\n"));
1711 DEBUG(0,("Only one of I,X,F must be specified\n"));
1718 DEBUG(0,("Only one of I,X,F must be specified\n"));
1724 DEBUG(0, ("tar_re_search set\n"));
1725 tar_re_search = True;
1728 if (tar_type == 'c') {
1729 DEBUG(0, ("dry_run set\n"));
1732 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1737 DEBUG(0,("Unknown tar option\n"));
1742 printf("Option T must be followed by one of c or x.\n");
1746 /* tar_excl is true if cliplist lists files to be included.
1747 * Both 'I' and 'F' mean include. */
1748 tar_excl=tar_clipfl!='X';
1750 if (tar_clipfl=='F') {
1751 if (argc-Optind-1 != 1) {
1752 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1755 if (! read_inclusion_file(argv[Optind+1])) {
1758 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1763 cliplist=argv+Optind+1;
1764 clipn=argc-Optind-1;
1767 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1768 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1774 for (clipcount = 0; clipcount < clipn; clipcount++) {
1776 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1778 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1779 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1784 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1785 tmplist[clipcount] = tmpstr;
1786 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1788 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1791 must_free_cliplist = True;
1794 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1798 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1800 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1805 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1809 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1811 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1817 clipn=argc-Optind-1;
1818 cliplist=argv+Optind+1;
1822 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1823 /* Sets tar handle to either 0 or 1, as appropriate */
1824 tarhandle=(tar_type=='c');
1826 * Make sure that dbf points to stderr if we are using stdout for
1832 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1835 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1840 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1841 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1843 DEBUG(0,("Error opening local file %s - %s\n",
1844 argv[Optind], strerror(errno)));