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
42 Convert list of tokens to array; dependent on above routine.
44 static char **toktocliplist(char *ptr, int *ctok, const char *sep)
53 while(*s && strchr_m(sep,*s))
62 while(*s && (!strchr_m(sep,*s)))
64 while(*s && strchr_m(sep,*s))
71 if (!(ret=iret=malloc(ictok*sizeof(char *))))
85 static int clipfind(char **aret, int ret, char *tok);
86 void dos_clean_name(char *s);
88 typedef struct file_info_struct file_info2;
90 struct file_info_struct
96 /* These times are normally kept in GMT */
100 char *name; /* This is dynamically allocate */
102 file_info2 *next, *prev; /* Used in the stack ... */
113 #define SEPARATORS " \t\n\r"
114 extern struct smbcli_state *cli;
116 /* These defines are for the do_setrattr routine, to indicate
117 * setting and reseting of file attributes in the function call */
121 static uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
123 #ifndef CLIENT_TIMEOUT
124 #define CLIENT_TIMEOUT (30*1000)
127 static char *tarbuf, *buffer_p;
128 static int tp, ntarf, tbufsiz;
130 /* Incremental mode */
131 static BOOL tar_inc=False;
132 /* Reset archive bit */
133 static BOOL tar_reset=False;
134 /* Include / exclude mode (true=include, false=exclude) */
135 static BOOL tar_excl=True;
136 /* use regular expressions for search on file names */
137 static BOOL tar_re_search=False;
141 /* Do not dump anything, just calculate sizes */
142 static BOOL dry_run=False;
143 /* Dump files with System attribute */
144 static BOOL tar_system=True;
145 /* Dump files with Hidden attribute */
146 static BOOL tar_hidden=True;
147 /* Be noisy - make a catalogue */
148 static BOOL tar_noisy=True;
149 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
152 static char **cliplist=NULL;
154 static BOOL must_free_cliplist = False;
156 extern BOOL lowercase;
157 extern uint16_t cnum;
158 extern BOOL readbraw_supported;
160 extern pstring cur_dir;
161 extern int get_total_time_ms;
162 extern int get_total_size;
164 static int blocksize=20;
165 static int tarhandle;
167 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
168 const char *amode, uint8_t ftype);
169 static void do_atar(char *rname,const char *lname,file_info *finfo1);
170 static void do_tar(file_info *finfo);
171 static void oct_it(uint64_t value, int ndgs, char *p);
172 static void fixtarname(char *tptr, const char *fp, int l);
173 static int dotarbuf(int f, char *b, int n);
174 static void dozerobuf(int f, int n);
175 static void dotareof(int f);
176 static void initarbuf(void);
178 /* restore functions */
179 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
180 static long unoct(char *p, int ndgs);
181 static void do_tarput(void);
182 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
185 * tar specific utitlities
188 /*******************************************************************
189 Create a string of size size+1 (for the null)
190 *******************************************************************/
191 static char *string_create_s(int size)
195 tmp = (char *)malloc(size+1);
199 DEBUG(0, ("Out of memory in string_create_s\n"));
207 /****************************************************************************
208 Write a tar header to buffer
209 ****************************************************************************/
210 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
211 const char *amode, uint8_t ftype)
217 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
219 memset(hb.dummy, 0, sizeof(hb.dummy));
222 if (l >= NAMSIZ - 1) {
223 /* write a GNU tar style long header */
225 b = (char *)malloc(l+TBLOCK+100);
227 DEBUG(0,("out of memory\n"));
230 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
231 memset(b, 0, l+TBLOCK+100);
232 fixtarname(b, aname, l);
234 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
235 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
239 /* use l + 1 to do the null too */
240 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
243 strlower(hb.dbuf.name);
245 /* write out a "standard" tar format header */
247 hb.dbuf.name[NAMSIZ-1]='\0';
248 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
249 oct_it((uint64_t)0, 8, hb.dbuf.uid);
250 oct_it((uint64_t)0, 8, hb.dbuf.gid);
251 oct_it((uint64_t) size, 13, hb.dbuf.size);
252 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
253 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
254 memset(hb.dbuf.linkname, 0, NAMSIZ);
255 hb.dbuf.linkflag=ftype;
257 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
259 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
260 hb.dbuf.chksum[6] = '\0';
262 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
265 /****************************************************************************
266 Read a tar header into a hblock structure, and validate
267 ***************************************************************************/
268 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
275 * read in a "standard" tar format header - we're not that interested
276 * in that many fields, though
279 /* check the checksum */
280 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
285 /* compensate for blanks in chksum header */
286 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
289 chk += ' ' * sizeof(hb->dbuf.chksum);
291 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
293 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
294 chk, fchk, hb->dbuf.chksum));
298 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
299 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
303 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
305 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
310 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
312 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
313 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
314 strlen(hb->dbuf.name) + 1, True);
316 /* can't handle some links at present */
317 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
318 if (hb->dbuf.linkflag == 0) {
319 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
322 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
323 /* Do nothing here at the moment. do_tarput will handle this
324 as long as the longlink gets back to it, as it has to advance
325 the buffer pointer, etc */
328 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
334 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
335 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
337 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
340 finfo->mode=0; /* we don't care about mode at the moment, we'll
341 * just make it a regular file */
343 * Bug fix by richard@sj.co.uk
345 * REC: restore times correctly (as does tar)
346 * We only get the modification time of the file; set the creation time
347 * from the mod. time, and the access time to current time
349 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
350 finfo->atime = time(NULL);
351 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
356 /****************************************************************************
357 Write out the tar buffer to tape or wherever
358 ****************************************************************************/
359 static int dotarbuf(int f, char *b, int n)
366 /* This routine and the next one should be the only ones that do write()s */
367 if (tp + n >= tbufsiz)
372 memcpy(tarbuf + tp, b, diff);
373 fail=fail && (1+write(f, tarbuf, tbufsiz));
380 fail=fail && (1 + write(f, b, tbufsiz));
386 memcpy(tarbuf+tp, b, n);
390 return(fail ? writ : 0);
393 /****************************************************************************
394 Write zeros to buffer / tape
395 ****************************************************************************/
396 static void dozerobuf(int f, int n)
398 /* short routine just to write out n zeros to buffer -
399 * used to round files to nearest block
400 * and to do tar EOFs */
407 memset(tarbuf+tp, 0, tbufsiz-tp);
409 write(f, tarbuf, tbufsiz);
410 memset(tarbuf, 0, (tp+=n-tbufsiz));
414 memset(tarbuf+tp, 0, n);
419 /****************************************************************************
421 ****************************************************************************/
422 static void initarbuf(void)
424 /* initialize tar buffer */
425 tbufsiz=blocksize*TBLOCK;
426 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
428 /* reset tar buffer pointer and tar file counter and total dumped */
429 tp=0; ntarf=0; ttarf=0;
432 /****************************************************************************
433 Write two zero blocks at end of file
434 ****************************************************************************/
435 static void dotareof(int f)
437 SMB_STRUCT_STAT stbuf;
438 /* Two zero blocks at end of file, write out full buffer */
443 (void) dozerobuf(f, TBLOCK);
444 (void) dozerobuf(f, TBLOCK);
446 if (sys_fstat(f, &stbuf) == -1)
448 DEBUG(0, ("Couldn't stat file handle\n"));
452 /* Could be a pipe, in which case S_ISREG should fail,
453 * and we should write out at full size */
454 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
457 /****************************************************************************
458 (Un)mangle DOS pathname, make nonabsolute
459 ****************************************************************************/
460 static void fixtarname(char *tptr, const char *fp, int l)
462 /* add a '.' to start of file name, convert from ugly dos \'s in path
463 * to lovely unix /'s :-} */
466 safe_strcpy(tptr, fp, l);
467 string_replace(tptr, '\\', '/');
470 /****************************************************************************
471 Convert from decimal to octal string
472 ****************************************************************************/
473 static void oct_it (uint64_t value, int ndgs, char *p)
475 /* Converts long to octal string, pads with leading zeros */
477 /* skip final null, but do final space */
481 /* Loop does at least one digit */
483 p[--ndgs] = '0' + (char) (value & 7);
486 while (ndgs > 0 && value != 0);
488 /* Do leading zeros */
493 /****************************************************************************
494 Convert from octal string to long
495 ***************************************************************************/
496 static long unoct(char *p, int ndgs)
499 /* Converts octal string to long, ignoring any non-digit */
503 if (isdigit((int)*p))
504 value = (value << 3) | (long) (*p - '0');
512 /****************************************************************************
513 Compare two strings in a slash insensitive way, allowing s1 to match s2
514 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
515 a file in any subdirectory of s1, declare a match.
516 ***************************************************************************/
517 static int strslashcmp(char *s1, char *s2)
523 || tolower(*s1) == tolower(*s2)
524 || (*s1 == '\\' && *s2=='/')
525 || (*s1 == '/' && *s2=='\\'))) {
529 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
532 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
534 /* ignore trailing slash on s1 */
535 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
537 /* check for s1 is an "initial" string of s2 */
538 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
544 /****************************************************************************
545 Ensure a remote path exists (make if necessary)
546 ***************************************************************************/
547 static BOOL ensurepath(char *fname)
549 /* *must* be called with buffer ready malloc'ed */
550 /* ensures path exists */
552 char *partpath, *ffname;
553 char *p=fname, *basehack;
555 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
557 partpath = string_create_s(strlen(fname));
558 ffname = string_create_s(strlen(fname));
560 if ((partpath == NULL) || (ffname == NULL)){
562 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
569 /* fname copied to ffname so can strtok */
571 safe_strcpy(ffname, fname, strlen(fname));
573 /* do a `basename' on ffname, so don't try and make file name directory */
574 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
579 p=strtok(ffname, "\\");
583 safe_strcat(partpath, p, strlen(fname) + 1);
585 if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, partpath))) {
586 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, partpath)))
588 DEBUG(0, ("Error mkdirhiering\n"));
592 DEBUG(3, ("mkdirhiering %s\n", partpath));
596 safe_strcat(partpath, "\\", strlen(fname) + 1);
597 p = strtok(NULL,"/\\");
603 static int padit(char *buf, int bufsize, int padsize)
608 DEBUG(5, ("Padding with %d zeros\n", padsize));
609 memset(buf, 0, bufsize);
610 while( !berr && padsize > 0 ) {
611 bytestowrite= MIN(bufsize, padsize);
612 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
613 padsize -= bytestowrite;
620 static void do_setrattr(char *name, uint16_t attr, int set)
624 if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, name, &oldattr, NULL, NULL)))
627 if (set == ATTRSET) {
630 attr = oldattr & ~attr;
633 if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, name, attr, 0))) {
634 DEBUG(1,("setatr failed: %s\n", smbcli_errstr(cli->tree)));
639 /****************************************************************************
640 append one remote file to the tar file
641 ***************************************************************************/
642 static void do_atar(char *rname,const char *lname,file_info *finfo1)
648 BOOL close_done = False;
649 BOOL shallitime=True;
651 int read_size = 65520;
654 struct timeval tp_start;
655 GetTimeOfDay(&tp_start);
657 ftype = '0'; /* An ordinary file ... */
660 finfo.size = finfo1 -> size;
661 finfo.mode = finfo1 -> mode;
662 finfo.uid = finfo1 -> uid;
663 finfo.gid = finfo1 -> gid;
664 finfo.mtime = finfo1 -> mtime;
665 finfo.atime = finfo1 -> atime;
666 finfo.ctime = finfo1 -> ctime;
667 finfo.name = discard_const_p(char, finfo1 -> name);
675 DEBUG(3,("skipping file %s of size %12.0f bytes\n",
677 (double)finfo.size));
679 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
684 fnum = smbcli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
686 dos_clean_name(rname);
689 DEBUG(0,("%s opening remote file %s (%s)\n",
690 smbcli_errstr(cli->tree),rname, cur_dir));
694 finfo.name = string_create_s(strlen(rname));
695 if (finfo.name == NULL) {
696 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
700 safe_strcpy(finfo.name,rname, strlen(rname));
703 if (NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime))) {
704 DEBUG(0, ("getattrE: %s\n", smbcli_errstr(cli->tree)));
708 finfo.ctime = finfo.mtime;
711 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
713 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
715 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
718 else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
720 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
723 else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
725 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
730 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
735 /* write a tar header, don't bother with mode - just set to 100644 */
736 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
738 while (nread < finfo.size && !close_done) {
740 DEBUG(3,("nread=%.0f\n",(double)nread));
742 datalen = smbcli_read(cli->tree, fnum, data, nread, read_size);
745 DEBUG(0,("Error reading file %s : %s\n", rname, smbcli_errstr(cli->tree)));
751 /* if file size has increased since we made file size query, truncate
752 read so tar header for this file will be correct.
755 if (nread > finfo.size) {
756 datalen -= nread - finfo.size;
757 DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
760 /* add received bits of file to buffer - dotarbuf will
761 * write out in 512 byte intervals */
762 if (dotarbuf(tarhandle,data,datalen) != datalen) {
763 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
768 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
775 /* pad tar file with zero's if we couldn't get entire file */
776 if (nread < finfo.size) {
777 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
778 if (padit(data, sizeof(data), finfo.size - nread))
779 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
782 /* round tar file to nearest block */
783 if (finfo.size % TBLOCK)
784 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
786 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
790 smbcli_close(cli->tree, fnum);
794 struct timeval tp_end;
797 /* if shallitime is true then we didn't skip */
798 if (tar_reset && !dry_run)
799 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
801 GetTimeOfDay(&tp_end);
803 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
804 (tp_end.tv_usec - tp_start.tv_usec)/1000;
805 get_total_time_ms += this_time;
806 get_total_size += finfo.size;
810 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
811 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
815 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
816 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
817 finfo.size / MAX(0.001, (1.024*this_time)),
818 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
822 /****************************************************************************
823 Append single file to tar file (or not)
824 ***************************************************************************/
825 static void do_tar(file_info *finfo)
829 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
832 /* Is it on the exclude list ? */
833 if (!tar_excl && clipn) {
836 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
838 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
839 *(exclaim+strlen(exclaim)-1)='\0';
841 safe_strcat(exclaim, "\\", sizeof(pstring));
842 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
844 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
846 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
848 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
850 (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
852 DEBUG(3,("Skipping file %s\n", exclaim));
857 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
859 pstring saved_curdir;
862 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
864 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));
866 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
867 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
869 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
871 /* write a tar directory, don't bother with mode - just set it to
873 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
875 DEBUG(0,(" directory %s\n", cur_dir));
877 ntarf++; /* Make sure we have a file on there */
878 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
879 safe_strcat(mtar_mask,"*", sizeof(pstring));
880 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
881 do_list(mtar_mask, attribute, do_tar, False, True);
882 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
886 safe_strcpy(rname,cur_dir, sizeof(pstring));
887 safe_strcat(rname,finfo->name, sizeof(pstring));
888 do_atar(rname,finfo->name,finfo);
892 /****************************************************************************
893 Convert from UNIX to DOS file names
894 ***************************************************************************/
895 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
897 /* remove '.' from start of file name, convert from unix /'s to
898 * dos \'s in path. Kill any absolute path names. But only if first!
901 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
908 if (*fp == '\\' || *fp == '/') {
914 safe_strcpy(tptr, fp, l);
915 string_replace(tptr, '/', '\\');
919 /****************************************************************************
920 Move to the next block in the buffer, which may mean read in another set of
921 blocks. FIXME, we should allow more than one block to be skipped.
922 ****************************************************************************/
923 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
925 int bufread, total = 0;
927 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
931 if (*bufferp >= (ltarbuf + bufsiz)) {
933 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
936 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
937 * Fixes bug where read can return short if coming from
941 bufread = read(tarhandle, ltarbuf, bufsiz);
944 while (total < bufsiz) {
945 if (bufread < 0) { /* An error, return false */
946 return (total > 0 ? -2 : bufread);
954 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
958 DEBUG(5, ("Total bytes read ... %i\n", total));
968 /* Skip a file, even if it includes a long file name? */
969 static int skip_file(int skipsize)
971 int dsize = skipsize;
973 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
975 /* FIXME, we should skip more than one block at a time */
979 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
981 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
993 /*************************************************************
994 Get a file from the tar file and store it.
995 When this is called, tarbuf already contains the first
996 file block. This is a bit broken & needs fixing.
997 **************************************************************/
999 static int get_file(file_info2 finfo)
1001 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
1003 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
1005 if (ensurepath(finfo.name) &&
1006 (fnum=smbcli_open(cli->tree, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1007 DEBUG(0, ("abandoning restore\n"));
1011 /* read the blocks from the tar file and write to the remote file */
1013 rsize = finfo.size; /* This is how much to write */
1017 /* We can only write up to the end of the buffer */
1019 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1020 dsize = MIN(dsize, rsize); /* Should be only what is left */
1021 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1023 if (smbcli_write(cli->tree, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1024 DEBUG(0, ("Error writing remote file\n"));
1031 /* Now figure out how much to move in the buffer */
1033 /* FIXME, we should skip more than one block at a time */
1035 /* First, skip any initial part of the part written that is left over */
1036 /* from the end of the first TBLOCK */
1038 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1040 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1043 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1044 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1052 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053 * If the file being extracted is an exact multiple of
1054 * TBLOCK bytes then we don't want to extract the next
1055 * block from the tarfile here, as it will be done in
1056 * the caller of get_file().
1059 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060 ((rsize == 0) && (dsize > TBLOCK))) {
1062 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1074 /* Now close the file ... */
1076 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
1077 DEBUG(0, ("Error closing remote file\n"));
1081 /* Now we update the creation date ... */
1083 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1085 if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, finfo.name, finfo.mode, finfo.mtime))) {
1086 if (tar_real_noisy) {
1087 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1088 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1094 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1099 /* Create a directory. We just ensure that the path exists and return as there
1100 is no file associated with a directory
1102 static int get_dir(file_info2 finfo)
1105 DEBUG(0, ("restore directory %s\n", finfo.name));
1107 if (!ensurepath(finfo.name)) {
1109 DEBUG(0, ("Problems creating directory\n"));
1118 /* Get a file with a long file name ... first file has file name, next file
1119 has the data. We only want the long file name, as the loop in do_tarput
1120 will deal with the rest.
1122 static char * get_longfilename(file_info2 finfo)
1124 int namesize = finfo.size + strlen(cur_dir) + 2;
1125 char *longname = malloc(namesize);
1126 int offset = 0, left = finfo.size;
1129 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1130 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1132 if (longname == NULL) {
1134 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1135 (int)(finfo.size + strlen(cur_dir) + 2)));
1139 /* First, add cur_dir to the long file name */
1141 if (strlen(cur_dir) > 0) {
1142 strncpy(longname, cur_dir, namesize);
1143 offset = strlen(cur_dir);
1146 /* Loop through the blocks picking up the name */
1150 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1152 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1157 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1158 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1169 static void do_tarput(void)
1172 struct timeval tp_start;
1173 char *longfilename = NULL, linkflag;
1176 GetTimeOfDay(&tp_start);
1178 DEBUG(5, ("RJS do_tarput called ...\n"));
1180 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1182 /* Now read through those files ... */
1186 /* Get us to the next block, or the first block first time around */
1188 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1190 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1196 DEBUG(5, ("Reading the next header ...\n"));
1198 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1200 case -2: /* Hmm, not good, but not fatal */
1201 DEBUG(0, ("Skipping %s...\n", finfo.name));
1202 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1203 !skip_file(finfo.size)) {
1205 DEBUG(0, ("Short file, bailing out...\n"));
1213 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1216 case 0: /* chksum is zero - looks like an EOF */
1217 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1218 return; /* Hmmm, bad here ... */
1227 /* Now, do we have a long file name? */
1229 if (longfilename != NULL) {
1231 SAFE_FREE(finfo.name); /* Free the space already allocated */
1232 finfo.name = longfilename;
1233 longfilename = NULL;
1237 /* Well, now we have a header, process the file ... */
1239 /* Should we skip the file? We have the long name as well here */
1242 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1244 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1246 || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1249 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1253 skip_file(finfo.size);
1258 /* We only get this far if we should process the file */
1259 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1263 case '0': /* Should use symbolic names--FIXME */
1266 * Skip to the next block first, so we can get the file, FIXME, should
1267 * be in get_file ...
1268 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1269 * Fixes bug where file size in tarfile is zero.
1272 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1273 DEBUG(0, ("Short file, bailing out...\n"));
1276 if (!get_file(finfo)) {
1277 DEBUG(0, ("Abandoning restore\n"));
1284 if (!get_dir(finfo)) {
1285 DEBUG(0, ("Abandoning restore \n"));
1291 longfilename = get_longfilename(finfo);
1292 if (!longfilename) {
1293 DEBUG(0, ("abandoning restore\n"));
1297 DEBUG(5, ("Long file name: %s\n", longfilename));
1301 skip_file(finfo.size); /* Don't handle these yet */
1313 * samba interactive commands
1316 /****************************************************************************
1318 ***************************************************************************/
1319 int cmd_block(const char **cmd_ptr)
1324 if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)))
1326 DEBUG(0, ("blocksize <n>\n"));
1331 if (block < 0 || block > 65535)
1333 DEBUG(0, ("blocksize out of range"));
1338 DEBUG(2,("blocksize is now %d\n", blocksize));
1343 /****************************************************************************
1344 command to set incremental / reset mode
1345 ***************************************************************************/
1346 int cmd_tarmode(const char **cmd_ptr)
1350 while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1351 if (strequal(buf, "full"))
1353 else if (strequal(buf, "inc"))
1355 else if (strequal(buf, "reset"))
1357 else if (strequal(buf, "noreset"))
1359 else if (strequal(buf, "system"))
1361 else if (strequal(buf, "nosystem"))
1363 else if (strequal(buf, "hidden"))
1365 else if (strequal(buf, "nohidden"))
1367 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1369 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1371 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1374 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1375 tar_inc ? "incremental" : "full",
1376 tar_system ? "system" : "nosystem",
1377 tar_hidden ? "hidden" : "nohidden",
1378 tar_reset ? "reset" : "noreset",
1379 tar_noisy ? "verbose" : "quiet"));
1384 /****************************************************************************
1385 Feeble attrib command
1386 ***************************************************************************/
1387 int cmd_setmode(const char **cmd_ptr)
1395 attra[0] = attra[1] = 0;
1397 if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)))
1399 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1403 safe_strcpy(fname, cur_dir, sizeof(pstring));
1404 safe_strcat(fname, buf, sizeof(pstring));
1406 while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1415 case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1417 case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1419 case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1421 case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1423 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1428 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1430 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1434 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1435 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1436 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1441 /****************************************************************************
1442 Principal command for creating / extracting
1443 ***************************************************************************/
1444 int cmd_tar(char **cmd_ptr)
1450 if (!next_token((const char **)cmd_ptr,buf,NULL,sizeof(buf)))
1452 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1456 argl=toktocliplist(*cmd_ptr, &argcl, NULL);
1457 if (!tar_parseargs(argcl, argl, buf, 0))
1467 /****************************************************************************
1468 Command line (option) version
1469 ***************************************************************************/
1470 int process_tar(void)
1486 if (clipn && tar_excl) {
1490 for (i=0; i<clipn; i++) {
1491 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1493 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1494 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1497 if (strrchr_m(cliplist[i], '\\')) {
1500 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1502 if (*cliplist[i]=='\\') {
1503 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1505 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1506 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1508 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1509 *(strrchr_m(cur_dir, '\\')+1)='\0';
1511 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1512 do_list(tarmac,attribute,do_tar, False, True);
1513 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1515 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1516 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1517 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1518 do_list(tarmac,attribute,do_tar, False, True);
1523 safe_strcpy(mask,cur_dir, sizeof(pstring));
1524 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1525 safe_strcat(mask,"\\*", sizeof(pstring));
1526 do_list(mask,attribute,do_tar,False, True);
1529 if (ntarf) dotareof(tarhandle);
1533 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1534 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1538 if (must_free_cliplist) {
1540 for (i = 0; i < clipn; ++i) {
1541 SAFE_FREE(cliplist[i]);
1543 SAFE_FREE(cliplist);
1546 must_free_cliplist = False;
1552 /****************************************************************************
1553 Find a token (filename) in a clip list
1554 ***************************************************************************/
1555 static int clipfind(char **aret, int ret, char *tok)
1557 if (aret==NULL) return 0;
1559 /* ignore leading slashes or dots in token */
1560 while(strchr_m("/\\.", *tok)) tok++;
1565 /* ignore leading slashes or dots in list */
1566 while(strchr_m("/\\.", *pkey)) pkey++;
1568 if (!strslashcmp(pkey, tok)) return 1;
1574 /****************************************************************************
1575 Read list of files to include from the file and initialize cliplist
1577 ***************************************************************************/
1578 static int read_inclusion_file(char *filename)
1580 XFILE *inclusion = NULL;
1581 char buf[MAXPATHLEN + 1];
1582 char *inclusion_buffer = NULL;
1583 int inclusion_buffer_size = 0;
1584 int inclusion_buffer_sofar = 0;
1591 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1592 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1593 /* XXX It would be better to include a reason for failure, but without
1594 * autoconf, it's hard to use strerror, sys_errlist, etc.
1596 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1600 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1601 if (inclusion_buffer == NULL) {
1602 inclusion_buffer_size = 1024;
1603 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1604 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1610 if (buf[strlen(buf)-1] == '\n') {
1611 buf[strlen(buf)-1] = '\0';
1614 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1616 inclusion_buffer_size *= 2;
1617 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1619 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1620 inclusion_buffer_size));
1624 else inclusion_buffer = ib;
1627 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1628 inclusion_buffer_sofar += strlen(buf) + 1;
1631 x_fclose(inclusion);
1634 /* Allocate an array of clipn + 1 char*'s for cliplist */
1635 cliplist = malloc((clipn + 1) * sizeof(char *));
1636 if (cliplist == NULL) {
1637 DEBUG(0,("failure allocating memory for cliplist\n"));
1640 cliplist[clipn] = NULL;
1641 p = inclusion_buffer;
1642 for (i = 0; (! error) && (i < clipn); i++) {
1643 /* set current item to NULL so array will be null-terminated even if
1644 * malloc fails below. */
1646 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1647 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1650 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1651 cliplist[i] = tmpstr;
1652 if ((p = strchr_m(p, '\000')) == NULL) {
1653 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1659 must_free_cliplist = True;
1663 SAFE_FREE(inclusion_buffer);
1667 /* We know cliplist is always null-terminated */
1668 for (pp = cliplist; *pp; ++pp) {
1671 SAFE_FREE(cliplist);
1673 must_free_cliplist = False;
1678 /* cliplist and its elements are freed at the end of process_tar. */
1682 /****************************************************************************
1683 Parse tar arguments. Sets tar_type, tar_excl, etc.
1684 ***************************************************************************/
1685 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1687 char tar_clipfl='\0';
1689 /* Reset back to defaults - could be from interactive version
1690 * reset mode and archive mode left as they are though
1702 if (tar_type=='c') {
1703 printf("Tar must be followed by only one of c or x.\n");
1709 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1710 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1721 DEBUG(0,("Option N must be followed by valid file name\n"));
1724 SMB_STRUCT_STAT stbuf;
1725 extern time_t newer_than;
1727 if (sys_stat(argv[Optind], &stbuf) == 0) {
1728 newer_than = stbuf.st_mtime;
1729 DEBUG(1,("Getting files newer than %s",
1730 asctime(localtime(&newer_than))));
1733 DEBUG(0,("Error setting newer-than time\n"));
1746 DEBUG(0,("Only one of I,X,F must be specified\n"));
1753 DEBUG(0,("Only one of I,X,F must be specified\n"));
1760 DEBUG(0,("Only one of I,X,F must be specified\n"));
1766 DEBUG(0, ("tar_re_search set\n"));
1767 tar_re_search = True;
1770 if (tar_type == 'c') {
1771 DEBUG(0, ("dry_run set\n"));
1774 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1779 DEBUG(0,("Unknown tar option\n"));
1784 printf("Option T must be followed by one of c or x.\n");
1788 /* tar_excl is true if cliplist lists files to be included.
1789 * Both 'I' and 'F' mean include. */
1790 tar_excl=tar_clipfl!='X';
1792 if (tar_clipfl=='F') {
1793 if (argc-Optind-1 != 1) {
1794 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1797 if (! read_inclusion_file(argv[Optind+1])) {
1800 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1805 cliplist=argv+Optind+1;
1806 clipn=argc-Optind-1;
1809 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1810 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1816 for (clipcount = 0; clipcount < clipn; clipcount++) {
1818 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1820 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1821 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1826 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1827 tmplist[clipcount] = tmpstr;
1828 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1830 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1833 must_free_cliplist = True;
1836 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1840 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1842 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1847 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1851 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1853 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1859 clipn=argc-Optind-1;
1860 cliplist=argv+Optind+1;
1864 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1865 /* Sets tar handle to either 0 or 1, as appropriate */
1866 tarhandle=(tar_type=='c');
1868 * Make sure that dbf points to stderr if we are using stdout for
1872 setup_logging("clitar", DEBUG_STDERR);
1874 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1877 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1882 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1883 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1885 DEBUG(0,("Error opening local file %s - %s\n",
1886 argv[Optind], strerror(errno)));