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 struct cli_state *cli;
74 /* These defines are for the do_setrattr routine, to indicate
75 * setting and reseting of file attributes in the function call */
79 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
81 #ifndef CLIENT_TIMEOUT
82 #define CLIENT_TIMEOUT (30*1000)
85 static char *tarbuf, *buffer_p;
86 static int tp, ntarf, tbufsiz;
88 /* Incremental mode */
90 /* Reset archive bit */
92 /* Include / exclude mode (true=include, false=exclude) */
94 /* use regular expressions for search on file names */
95 BOOL tar_re_search=False;
99 /* Do not dump anything, just calculate sizes */
101 /* Dump files with System attribute */
102 BOOL tar_system=True;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden=True;
105 /* Be noisy - make a catalogue */
107 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
110 static char **cliplist=NULL;
112 static BOOL must_free_cliplist = False;
114 extern file_info def_finfo;
115 extern BOOL lowercase;
117 extern BOOL readbraw_supported;
119 extern pstring cur_dir;
120 extern int get_total_time_ms;
121 extern int get_total_size;
126 static void writetarheader(int f, char *aname, int size, time_t mtime,
127 char *amode, unsigned char ftype);
128 static void do_atar(char *rname,char *lname,file_info *finfo1);
129 static void do_tar(file_info *finfo);
130 static void oct_it(long value, int ndgs, char *p);
131 static void fixtarname(char *tptr, char *fp, int l);
132 static int dotarbuf(int f, char *b, int n);
133 static void dozerobuf(int f, int n);
134 static void dotareof(int f);
135 static void initarbuf(void);
137 /* restore functions */
138 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
139 static long unoct(char *p, int ndgs);
140 static void do_tarput(void);
141 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
144 * tar specific utitlities
147 /*******************************************************************
148 Create a string of size size+1 (for the null)
149 *******************************************************************/
150 static char *string_create_s(int size)
154 tmp = (char *)malloc(size+1);
158 DEBUG(0, ("Out of memory in string_create_s\n"));
166 /****************************************************************************
167 Write a tar header to buffer
168 ****************************************************************************/
169 static void writetarheader(int f, char *aname, int size, time_t mtime,
170 char *amode, unsigned char ftype)
176 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
178 memset(hb.dummy, 0, sizeof(hb.dummy));
181 if (l >= NAMSIZ - 1) {
182 /* write a GNU tar style long header */
184 b = (char *)malloc(l+TBLOCK+100);
186 DEBUG(0,("out of memory\n"));
189 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
190 memset(b, 0, l+TBLOCK+100);
191 fixtarname(b, aname, l);
193 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
194 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
198 /* use l + 1 to do the null too */
199 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
202 strlower(hb.dbuf.name);
204 /* write out a "standard" tar format header */
206 hb.dbuf.name[NAMSIZ-1]='\0';
207 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
208 oct_it(0L, 8, hb.dbuf.uid);
209 oct_it(0L, 8, hb.dbuf.gid);
210 oct_it((long) size, 13, hb.dbuf.size);
211 oct_it((long) mtime, 13, hb.dbuf.mtime);
212 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
213 memset(hb.dbuf.linkname, 0, NAMSIZ);
214 hb.dbuf.linkflag=ftype;
216 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
218 oct_it((long) 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 ***************************************************************************/
227 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
234 * read in a "standard" tar format header - we're not that interested
235 * in that many fields, though
238 /* check the checksum */
239 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
244 /* compensate for blanks in chksum header */
245 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
248 chk += ' ' * sizeof(hb->dbuf.chksum);
250 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
252 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
253 chk, fchk, hb->dbuf.chksum));
257 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
258 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
262 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));
269 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
271 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
272 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
273 strlen(hb->dbuf.name) + 1, True);
275 /* can't handle some links at present */
276 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
277 if (hb->dbuf.linkflag == 0) {
278 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
281 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
282 /* Do nothing here at the moment. do_tarput will handle this
283 as long as the longlink gets back to it, as it has to advance
284 the buffer pointer, etc */
287 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
293 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
294 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
299 finfo->mode=0; /* we don't care about mode at the moment, we'll
300 * just make it a regular file */
302 * Bug fix by richard@sj.co.uk
304 * REC: restore times correctly (as does tar)
305 * We only get the modification time of the file; set the creation time
306 * from the mod. time, and the access time to current time
308 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
309 finfo->atime = 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 ****************************************************************************/
318 static int dotarbuf(int f, char *b, int n)
325 /* This routine and the next one should be the only ones that do write()s */
326 if (tp + n >= tbufsiz)
331 memcpy(tarbuf + tp, b, diff);
332 fail=fail && (1+write(f, tarbuf, tbufsiz));
339 fail=fail && (1 + write(f, b, tbufsiz));
345 memcpy(tarbuf+tp, b, n);
349 return(fail ? writ : 0);
352 /****************************************************************************
353 Write zeros to buffer / tape
354 ****************************************************************************/
355 static void dozerobuf(int f, int n)
357 /* short routine just to write out n zeros to buffer -
358 * used to round files to nearest block
359 * and to do tar EOFs */
366 memset(tarbuf+tp, 0, tbufsiz-tp);
368 write(f, tarbuf, tbufsiz);
369 memset(tarbuf, 0, (tp+=n-tbufsiz));
373 memset(tarbuf+tp, 0, n);
378 /****************************************************************************
380 ****************************************************************************/
381 static void initarbuf(void)
383 /* initialize tar buffer */
384 tbufsiz=blocksize*TBLOCK;
385 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
387 /* reset tar buffer pointer and tar file counter and total dumped */
388 tp=0; ntarf=0; ttarf=0;
391 /****************************************************************************
392 Write two zero blocks at end of file
393 ****************************************************************************/
394 static void dotareof(int f)
396 SMB_STRUCT_STAT stbuf;
397 /* Two zero blocks at end of file, write out full buffer */
402 (void) dozerobuf(f, TBLOCK);
403 (void) dozerobuf(f, TBLOCK);
405 if (sys_fstat(f, &stbuf) == -1)
407 DEBUG(0, ("Couldn't stat file handle\n"));
411 /* Could be a pipe, in which case S_ISREG should fail,
412 * and we should write out at full size */
413 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
416 /****************************************************************************
417 (Un)mangle DOS pathname, make nonabsolute
418 ****************************************************************************/
419 static void fixtarname(char *tptr, char *fp, int l)
421 /* add a '.' to start of file name, convert from ugly dos \'s in path
422 * to lovely unix /'s :-} */
425 safe_strcpy(tptr, fp, l);
426 string_replace(tptr, '\\', '/');
429 /****************************************************************************
430 Convert from decimal to octal string
431 ****************************************************************************/
432 static void oct_it (long value, int ndgs, char *p)
434 /* Converts long to octal string, pads with leading zeros */
436 /* skip final null, but do final space */
440 /* Loop does at least one digit */
442 p[--ndgs] = '0' + (char) (value & 7);
445 while (ndgs > 0 && value != 0);
447 /* Do leading zeros */
452 /****************************************************************************
453 Convert from octal string to long
454 ***************************************************************************/
455 static long unoct(char *p, int ndgs)
458 /* Converts octal string to long, ignoring any non-digit */
462 if (isdigit((int)*p))
463 value = (value << 3) | (long) (*p - '0');
471 /****************************************************************************
472 Compare two strings in a slash insensitive way, allowing s1 to match s2
473 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
474 a file in any subdirectory of s1, declare a match.
475 ***************************************************************************/
476 static int strslashcmp(char *s1, char *s2)
482 || tolower(*s1) == tolower(*s2)
483 || (*s1 == '\\' && *s2=='/')
484 || (*s1 == '/' && *s2=='\\'))) {
488 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
493 /* ignore trailing slash on s1 */
494 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
496 /* check for s1 is an "initial" string of s2 */
497 if (*s2 == '/' || *s2 == '\\') return 0;
503 /****************************************************************************
504 Ensure a remote path exists (make if necessary)
505 ***************************************************************************/
506 static BOOL ensurepath(char *fname)
508 /* *must* be called with buffer ready malloc'ed */
509 /* ensures path exists */
511 char *partpath, *ffname;
512 char *p=fname, *basehack;
514 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
516 partpath = string_create_s(strlen(fname));
517 ffname = string_create_s(strlen(fname));
519 if ((partpath == NULL) || (ffname == NULL)){
521 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
528 /* fname copied to ffname so can strtok */
530 safe_strcpy(ffname, fname, strlen(fname));
532 /* do a `basename' on ffname, so don't try and make file name directory */
533 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
538 p=strtok(ffname, "\\");
542 safe_strcat(partpath, p, strlen(fname) + 1);
544 if (!cli_chkpath(cli, partpath)) {
545 if (!cli_mkdir(cli, partpath))
547 DEBUG(0, ("Error mkdirhiering\n"));
551 DEBUG(3, ("mkdirhiering %s\n", partpath));
555 safe_strcat(partpath, "\\", strlen(fname) + 1);
556 p = strtok(NULL,"/\\");
562 static int padit(char *buf, int bufsize, int padsize)
567 DEBUG(5, ("Padding with %d zeros\n", padsize));
568 memset(buf, 0, bufsize);
569 while( !berr && padsize > 0 ) {
570 bytestowrite= MIN(bufsize, padsize);
571 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
572 padsize -= bytestowrite;
579 static void do_setrattr(char *name, uint16 attr, int set)
583 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
585 if (set == ATTRSET) {
588 attr = oldattr & ~attr;
591 if (!cli_setatr(cli, name, attr, 0)) {
592 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
597 /****************************************************************************
598 append one remote file to the tar file
599 ***************************************************************************/
600 static void do_atar(char *rname,char *lname,file_info *finfo1)
606 BOOL close_done = False;
607 BOOL shallitime=True;
609 int read_size = 65520;
612 struct timeval tp_start;
613 GetTimeOfDay(&tp_start);
615 ftype = '0'; /* An ordinary file ... */
618 finfo.size = finfo1 -> size;
619 finfo.mode = finfo1 -> mode;
620 finfo.uid = finfo1 -> uid;
621 finfo.gid = finfo1 -> gid;
622 finfo.mtime = finfo1 -> mtime;
623 finfo.atime = finfo1 -> atime;
624 finfo.ctime = finfo1 -> ctime;
627 finfo.size = def_finfo.size;
628 finfo.mode = def_finfo.mode;
629 finfo.uid = def_finfo.uid;
630 finfo.gid = def_finfo.gid;
631 finfo.mtime = def_finfo.mtime;
632 finfo.atime = def_finfo.atime;
633 finfo.ctime = def_finfo.ctime;
638 DEBUG(3,("skipping file %s of size %d bytes\n",
642 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
647 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
649 dos_clean_name(rname);
652 DEBUG(0,("%s opening remote file %s (%s)\n",
653 cli_errstr(cli),rname, cur_dir));
657 finfo.name = string_create_s(strlen(rname));
658 if (finfo.name == NULL) {
659 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
663 safe_strcpy(finfo.name,rname, strlen(rname));
665 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
666 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
669 finfo.ctime = finfo.mtime;
672 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
674 if (tar_inc && !(finfo.mode & aARCH))
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
679 else if (!tar_system && (finfo.mode & aSYSTEM))
681 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
684 else if (!tar_hidden && (finfo.mode & aHIDDEN))
686 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
696 /* write a tar header, don't bother with mode - just set to 100644 */
697 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
699 while (nread < finfo.size && !close_done) {
701 DEBUG(3,("nread=%d\n",nread));
703 datalen = cli_read(cli, fnum, data, nread, read_size);
706 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
712 /* if file size has increased since we made file size query, truncate
713 read so tar header for this file will be correct.
716 if (nread > finfo.size) {
717 datalen -= nread - finfo.size;
718 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
721 /* add received bits of file to buffer - dotarbuf will
722 * 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 /* pad tar file with zero's if we couldn't get entire file */
737 if (nread < finfo.size) {
738 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
739 if (padit(data, sizeof(data), finfo.size - nread))
740 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
743 /* round tar file to nearest block */
744 if (finfo.size % TBLOCK)
745 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
747 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
751 cli_close(cli, fnum);
755 struct timeval tp_end;
758 /* if shallitime is true then we didn't skip */
759 if (tar_reset && !dry_run)
760 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
762 GetTimeOfDay(&tp_end);
764 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
765 (tp_end.tv_usec - tp_start.tv_usec)/1000;
766 get_total_time_ms += this_time;
767 get_total_size += finfo.size;
771 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
772 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
776 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
777 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
778 finfo.size / MAX(0.001, (1.024*this_time)),
779 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
783 /****************************************************************************
784 Append single file to tar file (or not)
785 ***************************************************************************/
786 static void do_tar(file_info *finfo)
790 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
793 /* Is it on the exclude list ? */
794 if (!tar_excl && clipn) {
797 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
799 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
800 *(exclaim+strlen(exclaim)-1)='\0';
802 safe_strcat(exclaim, "\\", sizeof(pstring));
803 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
805 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
807 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
809 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
811 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
813 DEBUG(3,("Skipping file %s\n", exclaim));
818 if (finfo->mode & aDIR)
820 pstring saved_curdir;
823 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
825 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));
827 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
828 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
830 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
832 /* write a tar directory, don't bother with mode - just set it to
834 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
836 DEBUG(0,(" directory %s\n", cur_dir));
838 ntarf++; /* Make sure we have a file on there */
839 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
840 safe_strcat(mtar_mask,"*", sizeof(pstring));
841 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
842 do_list(mtar_mask, attribute, do_tar, False, True);
843 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
847 safe_strcpy(rname,cur_dir, sizeof(pstring));
848 safe_strcat(rname,finfo->name, sizeof(pstring));
849 do_atar(rname,finfo->name,finfo);
853 /****************************************************************************
854 Convert from UNIX to DOS file names
855 ***************************************************************************/
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, '/', '\\');
880 /****************************************************************************
881 Move to the next block in the buffer, which may mean read in another set of
882 blocks. FIXME, we should allow more than one block to be skipped.
883 ****************************************************************************/
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));
929 /* Skip a file, even if it includes a long file name? */
930 static int skip_file(int skipsize)
932 int dsize = skipsize;
934 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
936 /* FIXME, we should skip more than one block at a time */
940 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
942 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
954 /*************************************************************
955 Get a file from the tar file and store it.
956 When this is called, tarbuf already contains the first
957 file block. This is a bit broken & needs fixing.
958 **************************************************************/
960 static int get_file(file_info2 finfo)
962 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
964 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
966 if (ensurepath(finfo.name) &&
967 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
968 DEBUG(0, ("abandoning restore\n"));
972 /* read the blocks from the tar file and write to the remote file */
974 rsize = finfo.size; /* This is how much to write */
978 /* We can only write up to the end of the buffer */
980 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
981 dsize = MIN(dsize, rsize); /* Should be only what is left */
982 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
984 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
985 DEBUG(0, ("Error writing remote file\n"));
992 /* Now figure out how much to move in the buffer */
994 /* FIXME, we should skip more than one block at a time */
996 /* First, skip any initial part of the part written that is left over */
997 /* from the end of the first TBLOCK */
999 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1001 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1004 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1005 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1013 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1014 * If the file being extracted is an exact multiple of
1015 * TBLOCK bytes then we don't want to extract the next
1016 * block from the tarfile here, as it will be done in
1017 * the caller of get_file().
1020 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1021 ((rsize == 0) && (dsize > TBLOCK))) {
1023 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1024 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1035 /* Now close the file ... */
1037 if (!cli_close(cli, fnum)) {
1038 DEBUG(0, ("Error closing remote file\n"));
1042 /* Now we update the creation date ... */
1044 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1046 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1047 if (tar_real_noisy) {
1048 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1049 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1055 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1060 /* Create a directory. We just ensure that the path exists and return as there
1061 is no file associated with a directory
1063 static int get_dir(file_info2 finfo)
1066 DEBUG(0, ("restore directory %s\n", finfo.name));
1068 if (!ensurepath(finfo.name)) {
1070 DEBUG(0, ("Problems creating directory\n"));
1079 /* Get a file with a long file name ... first file has file name, next file
1080 has the data. We only want the long file name, as the loop in do_tarput
1081 will deal with the rest.
1083 static char * get_longfilename(file_info2 finfo)
1085 int namesize = finfo.size + strlen(cur_dir) + 2;
1086 char *longname = malloc(namesize);
1087 int offset = 0, left = finfo.size;
1090 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1091 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1093 if (longname == NULL) {
1095 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1096 (int)(finfo.size + strlen(cur_dir) + 2)));
1100 /* First, add cur_dir to the long file name */
1102 if (strlen(cur_dir) > 0) {
1103 strncpy(longname, cur_dir, namesize);
1104 offset = strlen(cur_dir);
1107 /* Loop through the blocks picking up the name */
1111 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1113 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1118 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1119 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1130 static void do_tarput(void)
1133 struct timeval tp_start;
1134 char *longfilename = NULL, linkflag;
1137 GetTimeOfDay(&tp_start);
1139 DEBUG(5, ("RJS do_tarput called ...\n"));
1141 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1143 /* Now read through those files ... */
1147 /* Get us to the next block, or the first block first time around */
1149 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1151 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1157 DEBUG(5, ("Reading the next header ...\n"));
1159 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1161 case -2: /* Hmm, not good, but not fatal */
1162 DEBUG(0, ("Skipping %s...\n", finfo.name));
1163 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1164 !skip_file(finfo.size)) {
1166 DEBUG(0, ("Short file, bailing out...\n"));
1174 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1177 case 0: /* chksum is zero - looks like an EOF */
1178 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1179 return; /* Hmmm, bad here ... */
1188 /* Now, do we have a long file name? */
1190 if (longfilename != NULL) {
1192 SAFE_FREE(finfo.name); /* Free the space already allocated */
1193 finfo.name = longfilename;
1194 longfilename = NULL;
1198 /* Well, now we have a header, process the file ... */
1200 /* Should we skip the file? We have the long name as well here */
1203 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1205 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1207 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1210 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1214 skip_file(finfo.size);
1219 /* We only get this far if we should process the file */
1220 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1224 case '0': /* Should use symbolic names--FIXME */
1227 * Skip to the next block first, so we can get the file, FIXME, should
1228 * be in get_file ...
1229 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1230 * Fixes bug where file size in tarfile is zero.
1233 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1234 DEBUG(0, ("Short file, bailing out...\n"));
1237 if (!get_file(finfo)) {
1238 DEBUG(0, ("Abandoning restore\n"));
1245 if (!get_dir(finfo)) {
1246 DEBUG(0, ("Abandoning restore \n"));
1252 longfilename = get_longfilename(finfo);
1253 if (!longfilename) {
1254 DEBUG(0, ("abandoning restore\n"));
1258 DEBUG(5, ("Long file name: %s\n", longfilename));
1262 skip_file(finfo.size); /* Don't handle these yet */
1274 * samba interactive commands
1277 /****************************************************************************
1279 ***************************************************************************/
1285 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1287 DEBUG(0, ("blocksize <n>\n"));
1292 if (block < 0 || block > 65535)
1294 DEBUG(0, ("blocksize out of range"));
1299 DEBUG(2,("blocksize is now %d\n", blocksize));
1304 /****************************************************************************
1305 command to set incremental / reset mode
1306 ***************************************************************************/
1307 int 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"));
1345 /****************************************************************************
1346 Feeble attrib command
1347 ***************************************************************************/
1348 int cmd_setmode(void)
1356 attra[0] = attra[1] = 0;
1358 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1360 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1364 safe_strcpy(fname, cur_dir, sizeof(pstring));
1365 safe_strcat(fname, buf, sizeof(pstring));
1367 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1376 case 'r': attra[direct]|=aRONLY;
1378 case 'h': attra[direct]|=aHIDDEN;
1380 case 's': attra[direct]|=aSYSTEM;
1382 case 'a': attra[direct]|=aARCH;
1384 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1389 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1391 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1395 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1396 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1397 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1402 /****************************************************************************
1403 Principal command for creating / extracting
1404 ***************************************************************************/
1411 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1413 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1417 argl=toktocliplist(&argcl, NULL);
1418 if (!tar_parseargs(argcl, argl, buf, 0))
1428 /****************************************************************************
1429 Command line (option) version
1430 ***************************************************************************/
1431 int process_tar(void)
1447 if (clipn && tar_excl) {
1451 for (i=0; i<clipn; i++) {
1452 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1454 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1455 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1458 if (strrchr_m(cliplist[i], '\\')) {
1461 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1463 if (*cliplist[i]=='\\') {
1464 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1466 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1467 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1469 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1470 *(strrchr_m(cur_dir, '\\')+1)='\0';
1472 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1473 do_list(tarmac,attribute,do_tar, False, True);
1474 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1476 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1477 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1478 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1479 do_list(tarmac,attribute,do_tar, False, True);
1484 safe_strcpy(mask,cur_dir, sizeof(pstring));
1485 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1486 safe_strcat(mask,"\\*", sizeof(pstring));
1487 do_list(mask,attribute,do_tar,False, True);
1490 if (ntarf) dotareof(tarhandle);
1494 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1495 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1499 if (must_free_cliplist) {
1501 for (i = 0; i < clipn; ++i) {
1502 SAFE_FREE(cliplist[i]);
1504 SAFE_FREE(cliplist);
1507 must_free_cliplist = False;
1513 /****************************************************************************
1514 Find a token (filename) in a clip list
1515 ***************************************************************************/
1516 static int clipfind(char **aret, int ret, char *tok)
1518 if (aret==NULL) return 0;
1520 /* ignore leading slashes or dots in token */
1521 while(strchr_m("/\\.", *tok)) tok++;
1526 /* ignore leading slashes or dots in list */
1527 while(strchr_m("/\\.", *pkey)) pkey++;
1529 if (!strslashcmp(pkey, tok)) return 1;
1535 /****************************************************************************
1536 Read list of files to include from the file and initialize cliplist
1538 ***************************************************************************/
1539 static int read_inclusion_file(char *filename)
1541 XFILE *inclusion = NULL;
1542 char buf[MAXPATHLEN + 1];
1543 char *inclusion_buffer = NULL;
1544 int inclusion_buffer_size = 0;
1545 int inclusion_buffer_sofar = 0;
1552 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1553 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1554 /* XXX It would be better to include a reason for failure, but without
1555 * autoconf, it's hard to use strerror, sys_errlist, etc.
1557 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1561 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1562 if (inclusion_buffer == NULL) {
1563 inclusion_buffer_size = 1024;
1564 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1565 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1571 if (buf[strlen(buf)-1] == '\n') {
1572 buf[strlen(buf)-1] = '\0';
1575 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1577 inclusion_buffer_size *= 2;
1578 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1580 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1581 inclusion_buffer_size));
1585 else inclusion_buffer = ib;
1588 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1589 inclusion_buffer_sofar += strlen(buf) + 1;
1592 x_fclose(inclusion);
1595 /* Allocate an array of clipn + 1 char*'s for cliplist */
1596 cliplist = malloc((clipn + 1) * sizeof(char *));
1597 if (cliplist == NULL) {
1598 DEBUG(0,("failure allocating memory for cliplist\n"));
1601 cliplist[clipn] = NULL;
1602 p = inclusion_buffer;
1603 for (i = 0; (! error) && (i < clipn); i++) {
1604 /* set current item to NULL so array will be null-terminated even if
1605 * malloc fails below. */
1607 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1608 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1611 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1612 cliplist[i] = tmpstr;
1613 if ((p = strchr_m(p, '\000')) == NULL) {
1614 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1620 must_free_cliplist = True;
1624 SAFE_FREE(inclusion_buffer);
1628 /* We know cliplist is always null-terminated */
1629 for (pp = cliplist; *pp; ++pp) {
1632 SAFE_FREE(cliplist);
1634 must_free_cliplist = False;
1639 /* cliplist and its elements are freed at the end of process_tar. */
1643 /****************************************************************************
1644 Parse tar arguments. Sets tar_type, tar_excl, etc.
1645 ***************************************************************************/
1646 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1648 char tar_clipfl='\0';
1650 /* Reset back to defaults - could be from interactive version
1651 * reset mode and archive mode left as they are though
1663 if (tar_type=='c') {
1664 printf("Tar must be followed by only one of c or x.\n");
1670 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1671 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1682 DEBUG(0,("Option N must be followed by valid file name\n"));
1685 SMB_STRUCT_STAT stbuf;
1686 extern time_t newer_than;
1688 if (sys_stat(argv[Optind], &stbuf) == 0) {
1689 newer_than = stbuf.st_mtime;
1690 DEBUG(1,("Getting files newer than %s",
1691 asctime(LocalTime(&newer_than))));
1694 DEBUG(0,("Error setting newer-than time\n"));
1707 DEBUG(0,("Only one of I,X,F must be specified\n"));
1714 DEBUG(0,("Only one of I,X,F must be specified\n"));
1721 DEBUG(0,("Only one of I,X,F must be specified\n"));
1727 DEBUG(0, ("tar_re_search set\n"));
1728 tar_re_search = True;
1731 if (tar_type == 'c') {
1732 DEBUG(0, ("dry_run set\n"));
1735 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1740 DEBUG(0,("Unknown tar option\n"));
1745 printf("Option T must be followed by one of c or x.\n");
1749 /* tar_excl is true if cliplist lists files to be included.
1750 * Both 'I' and 'F' mean include. */
1751 tar_excl=tar_clipfl!='X';
1753 if (tar_clipfl=='F') {
1754 if (argc-Optind-1 != 1) {
1755 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1758 if (! read_inclusion_file(argv[Optind+1])) {
1761 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1766 cliplist=argv+Optind+1;
1767 clipn=argc-Optind-1;
1770 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1771 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1777 for (clipcount = 0; clipcount < clipn; clipcount++) {
1779 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1781 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1782 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1787 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1788 tmplist[clipcount] = tmpstr;
1789 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1791 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1794 must_free_cliplist = True;
1797 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1801 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1803 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1808 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1812 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1814 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1820 clipn=argc-Optind-1;
1821 cliplist=argv+Optind+1;
1825 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1826 /* Sets tar handle to either 0 or 1, as appropriate */
1827 tarhandle=(tar_type=='c');
1829 * Make sure that dbf points to stderr if we are using stdout for
1835 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1838 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1843 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1844 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1846 DEBUG(0,("Error opening local file %s - %s\n",
1847 argv[Optind], strerror(errno)));