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
41 static int clipfind(char **aret, int ret, char *tok);
42 void dos_clean_name(char *s);
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 #define SEPARATORS " \t\n\r"
70 extern struct smbcli_state *cli;
72 /* These defines are for the do_setrattr routine, to indicate
73 * setting and reseting of file attributes in the function call */
77 static uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
79 #ifndef CLIENT_TIMEOUT
80 #define CLIENT_TIMEOUT (30*1000)
83 static char *tarbuf, *buffer_p;
84 static int tp, ntarf, tbufsiz;
86 /* Incremental mode */
87 static BOOL tar_inc=False;
88 /* Reset archive bit */
89 static BOOL tar_reset=False;
90 /* Include / exclude mode (true=include, false=exclude) */
91 static BOOL tar_excl=True;
92 /* use regular expressions for search on file names */
93 static BOOL tar_re_search=False;
97 /* Do not dump anything, just calculate sizes */
98 static BOOL dry_run=False;
99 /* Dump files with System attribute */
100 static BOOL tar_system=True;
101 /* Dump files with Hidden attribute */
102 static BOOL tar_hidden=True;
103 /* Be noisy - make a catalogue */
104 static BOOL tar_noisy=True;
105 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
108 static char **cliplist=NULL;
110 static BOOL must_free_cliplist = False;
112 extern BOOL lowercase;
113 extern uint16_t cnum;
114 extern BOOL readbraw_supported;
116 extern pstring cur_dir;
117 extern int get_total_time_ms;
118 extern int get_total_size;
120 static int blocksize=20;
121 static int tarhandle;
123 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
124 const char *amode, uint8_t ftype);
125 static void do_atar(char *rname,char *lname,file_info *finfo1);
126 static void do_tar(file_info *finfo);
127 static void oct_it(uint64_t value, int ndgs, char *p);
128 static void fixtarname(char *tptr, const char *fp, int l);
129 static int dotarbuf(int f, char *b, int n);
130 static void dozerobuf(int f, int n);
131 static void dotareof(int f);
132 static void initarbuf(void);
134 /* restore functions */
135 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
136 static long unoct(char *p, int ndgs);
137 static void do_tarput(void);
138 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
141 * tar specific utitlities
144 /*******************************************************************
145 Create a string of size size+1 (for the null)
146 *******************************************************************/
147 static char *string_create_s(int size)
151 tmp = (char *)malloc(size+1);
155 DEBUG(0, ("Out of memory in string_create_s\n"));
163 /****************************************************************************
164 Write a tar header to buffer
165 ****************************************************************************/
166 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
167 const char *amode, uint8_t ftype)
173 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
175 memset(hb.dummy, 0, sizeof(hb.dummy));
178 if (l >= NAMSIZ - 1) {
179 /* write a GNU tar style long header */
181 b = (char *)malloc(l+TBLOCK+100);
183 DEBUG(0,("out of memory\n"));
186 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
187 memset(b, 0, l+TBLOCK+100);
188 fixtarname(b, aname, l);
190 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
191 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
195 /* use l + 1 to do the null too */
196 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
199 strlower(hb.dbuf.name);
201 /* write out a "standard" tar format header */
203 hb.dbuf.name[NAMSIZ-1]='\0';
204 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
205 oct_it((uint64_t)0, 8, hb.dbuf.uid);
206 oct_it((uint64_t)0, 8, hb.dbuf.gid);
207 oct_it((uint64_t) size, 13, hb.dbuf.size);
208 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
209 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
210 memset(hb.dbuf.linkname, 0, NAMSIZ);
211 hb.dbuf.linkflag=ftype;
213 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
215 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
216 hb.dbuf.chksum[6] = '\0';
218 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
221 /****************************************************************************
222 Read a tar header into a hblock structure, and validate
223 ***************************************************************************/
224 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
231 * read in a "standard" tar format header - we're not that interested
232 * in that many fields, though
235 /* check the checksum */
236 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
241 /* compensate for blanks in chksum header */
242 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
245 chk += ' ' * sizeof(hb->dbuf.chksum);
247 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
249 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
250 chk, fchk, hb->dbuf.chksum));
254 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
255 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
259 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
261 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
266 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
268 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
269 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
270 strlen(hb->dbuf.name) + 1, True);
272 /* can't handle some links at present */
273 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
274 if (hb->dbuf.linkflag == 0) {
275 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
278 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
279 /* Do nothing here at the moment. do_tarput will handle this
280 as long as the longlink gets back to it, as it has to advance
281 the buffer pointer, etc */
284 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
290 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
291 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
293 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
296 finfo->mode=0; /* we don't care about mode at the moment, we'll
297 * just make it a regular file */
299 * Bug fix by richard@sj.co.uk
301 * REC: restore times correctly (as does tar)
302 * We only get the modification time of the file; set the creation time
303 * from the mod. time, and the access time to current time
305 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
306 finfo->atime = time(NULL);
307 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
312 /****************************************************************************
313 Write out the tar buffer to tape or wherever
314 ****************************************************************************/
315 static int dotarbuf(int f, char *b, int n)
322 /* This routine and the next one should be the only ones that do write()s */
323 if (tp + n >= tbufsiz)
328 memcpy(tarbuf + tp, b, diff);
329 fail=fail && (1+write(f, tarbuf, tbufsiz));
336 fail=fail && (1 + write(f, b, tbufsiz));
342 memcpy(tarbuf+tp, b, n);
346 return(fail ? writ : 0);
349 /****************************************************************************
350 Write zeros to buffer / tape
351 ****************************************************************************/
352 static void dozerobuf(int f, int n)
354 /* short routine just to write out n zeros to buffer -
355 * used to round files to nearest block
356 * and to do tar EOFs */
363 memset(tarbuf+tp, 0, tbufsiz-tp);
365 write(f, tarbuf, tbufsiz);
366 memset(tarbuf, 0, (tp+=n-tbufsiz));
370 memset(tarbuf+tp, 0, n);
375 /****************************************************************************
377 ****************************************************************************/
378 static void initarbuf(void)
380 /* initialize tar buffer */
381 tbufsiz=blocksize*TBLOCK;
382 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
384 /* reset tar buffer pointer and tar file counter and total dumped */
385 tp=0; ntarf=0; ttarf=0;
388 /****************************************************************************
389 Write two zero blocks at end of file
390 ****************************************************************************/
391 static void dotareof(int f)
393 SMB_STRUCT_STAT stbuf;
394 /* Two zero blocks at end of file, write out full buffer */
399 (void) dozerobuf(f, TBLOCK);
400 (void) dozerobuf(f, TBLOCK);
402 if (sys_fstat(f, &stbuf) == -1)
404 DEBUG(0, ("Couldn't stat file handle\n"));
408 /* Could be a pipe, in which case S_ISREG should fail,
409 * and we should write out at full size */
410 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
413 /****************************************************************************
414 (Un)mangle DOS pathname, make nonabsolute
415 ****************************************************************************/
416 static void fixtarname(char *tptr, const char *fp, int l)
418 /* add a '.' to start of file name, convert from ugly dos \'s in path
419 * to lovely unix /'s :-} */
422 safe_strcpy(tptr, fp, l);
423 string_replace(tptr, '\\', '/');
426 /****************************************************************************
427 Convert from decimal to octal string
428 ****************************************************************************/
429 static void oct_it (uint64_t value, int ndgs, char *p)
431 /* Converts long to octal string, pads with leading zeros */
433 /* skip final null, but do final space */
437 /* Loop does at least one digit */
439 p[--ndgs] = '0' + (char) (value & 7);
442 while (ndgs > 0 && value != 0);
444 /* Do leading zeros */
449 /****************************************************************************
450 Convert from octal string to long
451 ***************************************************************************/
452 static long unoct(char *p, int ndgs)
455 /* Converts octal string to long, ignoring any non-digit */
459 if (isdigit((int)*p))
460 value = (value << 3) | (long) (*p - '0');
468 /****************************************************************************
469 Compare two strings in a slash insensitive way, allowing s1 to match s2
470 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
471 a file in any subdirectory of s1, declare a match.
472 ***************************************************************************/
473 static int strslashcmp(char *s1, char *s2)
479 || tolower(*s1) == tolower(*s2)
480 || (*s1 == '\\' && *s2=='/')
481 || (*s1 == '/' && *s2=='\\'))) {
485 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
488 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
490 /* ignore trailing slash on s1 */
491 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
493 /* check for s1 is an "initial" string of s2 */
494 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
500 /****************************************************************************
501 Ensure a remote path exists (make if necessary)
502 ***************************************************************************/
503 static BOOL ensurepath(char *fname)
505 /* *must* be called with buffer ready malloc'ed */
506 /* ensures path exists */
508 char *partpath, *ffname;
509 char *p=fname, *basehack;
511 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
513 partpath = string_create_s(strlen(fname));
514 ffname = string_create_s(strlen(fname));
516 if ((partpath == NULL) || (ffname == NULL)){
518 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
525 /* fname copied to ffname so can strtok */
527 safe_strcpy(ffname, fname, strlen(fname));
529 /* do a `basename' on ffname, so don't try and make file name directory */
530 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
535 p=strtok(ffname, "\\");
539 safe_strcat(partpath, p, strlen(fname) + 1);
541 if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, partpath))) {
542 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, partpath)))
544 DEBUG(0, ("Error mkdirhiering\n"));
548 DEBUG(3, ("mkdirhiering %s\n", partpath));
552 safe_strcat(partpath, "\\", strlen(fname) + 1);
553 p = strtok(NULL,"/\\");
559 static int padit(char *buf, int bufsize, int padsize)
564 DEBUG(5, ("Padding with %d zeros\n", padsize));
565 memset(buf, 0, bufsize);
566 while( !berr && padsize > 0 ) {
567 bytestowrite= MIN(bufsize, padsize);
568 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
569 padsize -= bytestowrite;
576 static void do_setrattr(char *name, uint16_t attr, int set)
580 if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, name, &oldattr, NULL, NULL)))
583 if (set == ATTRSET) {
586 attr = oldattr & ~attr;
589 if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, name, attr, 0))) {
590 DEBUG(1,("setatr failed: %s\n", smbcli_errstr(cli->tree)));
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
598 static void do_atar(char *rname,char *lname,file_info *finfo1)
604 BOOL close_done = False;
605 BOOL shallitime=True;
607 int read_size = 65520;
610 struct timeval tp_start;
611 GetTimeOfDay(&tp_start);
613 ftype = '0'; /* An ordinary file ... */
616 finfo.size = finfo1 -> size;
617 finfo.mode = finfo1 -> mode;
618 finfo.uid = finfo1 -> uid;
619 finfo.gid = finfo1 -> gid;
620 finfo.mtime = finfo1 -> mtime;
621 finfo.atime = finfo1 -> atime;
622 finfo.ctime = finfo1 -> ctime;
623 finfo.name = finfo1 -> name;
631 DEBUG(3,("skipping file %s of size %12.0f bytes\n",
633 (double)finfo.size));
635 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
640 fnum = smbcli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
642 dos_clean_name(rname);
645 DEBUG(0,("%s opening remote file %s (%s)\n",
646 smbcli_errstr(cli->tree),rname, cur_dir));
650 finfo.name = string_create_s(strlen(rname));
651 if (finfo.name == NULL) {
652 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
656 safe_strcpy(finfo.name,rname, strlen(rname));
659 if (NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime))) {
660 DEBUG(0, ("getattrE: %s\n", smbcli_errstr(cli->tree)));
664 finfo.ctime = finfo.mtime;
667 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
669 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
671 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
674 else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
676 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
679 else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
681 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
686 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
691 /* write a tar header, don't bother with mode - just set to 100644 */
692 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
694 while (nread < finfo.size && !close_done) {
696 DEBUG(3,("nread=%.0f\n",(double)nread));
698 datalen = smbcli_read(cli->tree, fnum, data, nread, read_size);
701 DEBUG(0,("Error reading file %s : %s\n", rname, smbcli_errstr(cli->tree)));
707 /* if file size has increased since we made file size query, truncate
708 read so tar header for this file will be correct.
711 if (nread > finfo.size) {
712 datalen -= nread - finfo.size;
713 DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
716 /* add received bits of file to buffer - dotarbuf will
717 * write out in 512 byte intervals */
718 if (dotarbuf(tarhandle,data,datalen) != datalen) {
719 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
724 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
731 /* pad tar file with zero's if we couldn't get entire file */
732 if (nread < finfo.size) {
733 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
734 if (padit(data, sizeof(data), finfo.size - nread))
735 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
738 /* round tar file to nearest block */
739 if (finfo.size % TBLOCK)
740 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
742 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
746 smbcli_close(cli->tree, fnum);
750 struct timeval tp_end;
753 /* if shallitime is true then we didn't skip */
754 if (tar_reset && !dry_run)
755 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
757 GetTimeOfDay(&tp_end);
759 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
760 (tp_end.tv_usec - tp_start.tv_usec)/1000;
761 get_total_time_ms += this_time;
762 get_total_size += finfo.size;
766 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
767 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
771 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
772 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
773 finfo.size / MAX(0.001, (1.024*this_time)),
774 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
778 /****************************************************************************
779 Append single file to tar file (or not)
780 ***************************************************************************/
781 static void do_tar(file_info *finfo)
785 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
788 /* Is it on the exclude list ? */
789 if (!tar_excl && clipn) {
792 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
794 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
795 *(exclaim+strlen(exclaim)-1)='\0';
797 safe_strcat(exclaim, "\\", sizeof(pstring));
798 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
800 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
802 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
804 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
806 (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
808 DEBUG(3,("Skipping file %s\n", exclaim));
813 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
815 pstring saved_curdir;
818 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
820 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));
822 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
823 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
825 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
827 /* write a tar directory, don't bother with mode - just set it to
829 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
831 DEBUG(0,(" directory %s\n", cur_dir));
833 ntarf++; /* Make sure we have a file on there */
834 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
835 safe_strcat(mtar_mask,"*", sizeof(pstring));
836 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
837 do_list(mtar_mask, attribute, do_tar, False, True);
838 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
842 safe_strcpy(rname,cur_dir, sizeof(pstring));
843 safe_strcat(rname,finfo->name, sizeof(pstring));
844 do_atar(rname,finfo->name,finfo);
848 /****************************************************************************
849 Convert from UNIX to DOS file names
850 ***************************************************************************/
851 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
853 /* remove '.' from start of file name, convert from unix /'s to
854 * dos \'s in path. Kill any absolute path names. But only if first!
857 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
864 if (*fp == '\\' || *fp == '/') {
870 safe_strcpy(tptr, fp, l);
871 string_replace(tptr, '/', '\\');
875 /****************************************************************************
876 Move to the next block in the buffer, which may mean read in another set of
877 blocks. FIXME, we should allow more than one block to be skipped.
878 ****************************************************************************/
879 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
881 int bufread, total = 0;
883 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
887 if (*bufferp >= (ltarbuf + bufsiz)) {
889 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
892 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
893 * Fixes bug where read can return short if coming from
897 bufread = read(tarhandle, ltarbuf, bufsiz);
900 while (total < bufsiz) {
901 if (bufread < 0) { /* An error, return false */
902 return (total > 0 ? -2 : bufread);
910 bufread = read(tarhandle, <arbuf[total], bufsiz - total);
914 DEBUG(5, ("Total bytes read ... %i\n", total));
924 /* Skip a file, even if it includes a long file name? */
925 static int skip_file(int skipsize)
927 int dsize = skipsize;
929 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
931 /* FIXME, we should skip more than one block at a time */
935 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
937 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
949 /*************************************************************
950 Get a file from the tar file and store it.
951 When this is called, tarbuf already contains the first
952 file block. This is a bit broken & needs fixing.
953 **************************************************************/
955 static int get_file(file_info2 finfo)
957 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
959 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
961 if (ensurepath(finfo.name) &&
962 (fnum=smbcli_open(cli->tree, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
963 DEBUG(0, ("abandoning restore\n"));
967 /* read the blocks from the tar file and write to the remote file */
969 rsize = finfo.size; /* This is how much to write */
973 /* We can only write up to the end of the buffer */
975 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
976 dsize = MIN(dsize, rsize); /* Should be only what is left */
977 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
979 if (smbcli_write(cli->tree, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
980 DEBUG(0, ("Error writing remote file\n"));
987 /* Now figure out how much to move in the buffer */
989 /* FIXME, we should skip more than one block at a time */
991 /* First, skip any initial part of the part written that is left over */
992 /* from the end of the first TBLOCK */
994 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
996 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
999 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1000 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1008 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1009 * If the file being extracted is an exact multiple of
1010 * TBLOCK bytes then we don't want to extract the next
1011 * block from the tarfile here, as it will be done in
1012 * the caller of get_file().
1015 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1016 ((rsize == 0) && (dsize > TBLOCK))) {
1018 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1019 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1030 /* Now close the file ... */
1032 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
1033 DEBUG(0, ("Error closing remote file\n"));
1037 /* Now we update the creation date ... */
1039 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1041 if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, finfo.name, finfo.mode, finfo.mtime))) {
1042 if (tar_real_noisy) {
1043 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1044 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1050 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1055 /* Create a directory. We just ensure that the path exists and return as there
1056 is no file associated with a directory
1058 static int get_dir(file_info2 finfo)
1061 DEBUG(0, ("restore directory %s\n", finfo.name));
1063 if (!ensurepath(finfo.name)) {
1065 DEBUG(0, ("Problems creating directory\n"));
1074 /* Get a file with a long file name ... first file has file name, next file
1075 has the data. We only want the long file name, as the loop in do_tarput
1076 will deal with the rest.
1078 static char * get_longfilename(file_info2 finfo)
1080 int namesize = finfo.size + strlen(cur_dir) + 2;
1081 char *longname = malloc(namesize);
1082 int offset = 0, left = finfo.size;
1085 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1086 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1088 if (longname == NULL) {
1090 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1091 (int)(finfo.size + strlen(cur_dir) + 2)));
1095 /* First, add cur_dir to the long file name */
1097 if (strlen(cur_dir) > 0) {
1098 strncpy(longname, cur_dir, namesize);
1099 offset = strlen(cur_dir);
1102 /* Loop through the blocks picking up the name */
1106 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1108 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1113 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1114 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1125 static void do_tarput(void)
1128 struct timeval tp_start;
1129 char *longfilename = NULL, linkflag;
1132 GetTimeOfDay(&tp_start);
1134 DEBUG(5, ("RJS do_tarput called ...\n"));
1136 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1138 /* Now read through those files ... */
1142 /* Get us to the next block, or the first block first time around */
1144 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1146 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1152 DEBUG(5, ("Reading the next header ...\n"));
1154 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1156 case -2: /* Hmm, not good, but not fatal */
1157 DEBUG(0, ("Skipping %s...\n", finfo.name));
1158 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1159 !skip_file(finfo.size)) {
1161 DEBUG(0, ("Short file, bailing out...\n"));
1169 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1172 case 0: /* chksum is zero - looks like an EOF */
1173 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1174 return; /* Hmmm, bad here ... */
1183 /* Now, do we have a long file name? */
1185 if (longfilename != NULL) {
1187 SAFE_FREE(finfo.name); /* Free the space already allocated */
1188 finfo.name = longfilename;
1189 longfilename = NULL;
1193 /* Well, now we have a header, process the file ... */
1195 /* Should we skip the file? We have the long name as well here */
1198 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1200 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1202 || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1205 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1209 skip_file(finfo.size);
1214 /* We only get this far if we should process the file */
1215 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1219 case '0': /* Should use symbolic names--FIXME */
1222 * Skip to the next block first, so we can get the file, FIXME, should
1223 * be in get_file ...
1224 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1225 * Fixes bug where file size in tarfile is zero.
1228 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1229 DEBUG(0, ("Short file, bailing out...\n"));
1232 if (!get_file(finfo)) {
1233 DEBUG(0, ("Abandoning restore\n"));
1240 if (!get_dir(finfo)) {
1241 DEBUG(0, ("Abandoning restore \n"));
1247 longfilename = get_longfilename(finfo);
1248 if (!longfilename) {
1249 DEBUG(0, ("abandoning restore\n"));
1253 DEBUG(5, ("Long file name: %s\n", longfilename));
1257 skip_file(finfo.size); /* Don't handle these yet */
1269 * samba interactive commands
1272 /****************************************************************************
1274 ***************************************************************************/
1280 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1282 DEBUG(0, ("blocksize <n>\n"));
1287 if (block < 0 || block > 65535)
1289 DEBUG(0, ("blocksize out of range"));
1294 DEBUG(2,("blocksize is now %d\n", blocksize));
1299 /****************************************************************************
1300 command to set incremental / reset mode
1301 ***************************************************************************/
1302 int cmd_tarmode(void)
1306 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1307 if (strequal(buf, "full"))
1309 else if (strequal(buf, "inc"))
1311 else if (strequal(buf, "reset"))
1313 else if (strequal(buf, "noreset"))
1315 else if (strequal(buf, "system"))
1317 else if (strequal(buf, "nosystem"))
1319 else if (strequal(buf, "hidden"))
1321 else if (strequal(buf, "nohidden"))
1323 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1325 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1327 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1330 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1331 tar_inc ? "incremental" : "full",
1332 tar_system ? "system" : "nosystem",
1333 tar_hidden ? "hidden" : "nohidden",
1334 tar_reset ? "reset" : "noreset",
1335 tar_noisy ? "verbose" : "quiet"));
1340 /****************************************************************************
1341 Feeble attrib command
1342 ***************************************************************************/
1343 int cmd_setmode(void)
1351 attra[0] = attra[1] = 0;
1353 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1355 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1359 safe_strcpy(fname, cur_dir, sizeof(pstring));
1360 safe_strcat(fname, buf, sizeof(pstring));
1362 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1371 case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1373 case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1375 case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1377 case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1379 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1384 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1386 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1390 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1391 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1392 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1406 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1408 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1412 argl=toktocliplist(&argcl, NULL);
1413 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) {
1497 SAFE_FREE(cliplist[i]);
1499 SAFE_FREE(cliplist);
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 SAFE_FREE(inclusion_buffer);
1623 /* We know cliplist is always null-terminated */
1624 for (pp = cliplist; *pp; ++pp) {
1627 SAFE_FREE(cliplist);
1629 must_free_cliplist = False;
1634 /* cliplist and its elements are freed at the end of process_tar. */
1638 /****************************************************************************
1639 Parse tar arguments. Sets tar_type, tar_excl, etc.
1640 ***************************************************************************/
1641 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1643 char tar_clipfl='\0';
1645 /* Reset back to defaults - could be from interactive version
1646 * reset mode and archive mode left as they are though
1658 if (tar_type=='c') {
1659 printf("Tar must be followed by only one of c or x.\n");
1665 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1666 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1677 DEBUG(0,("Option N must be followed by valid file name\n"));
1680 SMB_STRUCT_STAT stbuf;
1681 extern time_t newer_than;
1683 if (sys_stat(argv[Optind], &stbuf) == 0) {
1684 newer_than = stbuf.st_mtime;
1685 DEBUG(1,("Getting files newer than %s",
1686 asctime(localtime(&newer_than))));
1689 DEBUG(0,("Error setting newer-than time\n"));
1702 DEBUG(0,("Only one of I,X,F must be specified\n"));
1709 DEBUG(0,("Only one of I,X,F must be specified\n"));
1716 DEBUG(0,("Only one of I,X,F must be specified\n"));
1722 DEBUG(0, ("tar_re_search set\n"));
1723 tar_re_search = True;
1726 if (tar_type == 'c') {
1727 DEBUG(0, ("dry_run set\n"));
1730 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1735 DEBUG(0,("Unknown tar option\n"));
1740 printf("Option T must be followed by one of c or x.\n");
1744 /* tar_excl is true if cliplist lists files to be included.
1745 * Both 'I' and 'F' mean include. */
1746 tar_excl=tar_clipfl!='X';
1748 if (tar_clipfl=='F') {
1749 if (argc-Optind-1 != 1) {
1750 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1753 if (! read_inclusion_file(argv[Optind+1])) {
1756 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1761 cliplist=argv+Optind+1;
1762 clipn=argc-Optind-1;
1765 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1766 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1772 for (clipcount = 0; clipcount < clipn; clipcount++) {
1774 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1776 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1777 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1782 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1783 tmplist[clipcount] = tmpstr;
1784 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1786 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1789 must_free_cliplist = True;
1792 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1796 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1798 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1803 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1807 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1809 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1815 clipn=argc-Optind-1;
1816 cliplist=argv+Optind+1;
1820 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1821 /* Sets tar handle to either 0 or 1, as appropriate */
1822 tarhandle=(tar_type=='c');
1824 * Make sure that dbf points to stderr if we are using stdout for
1828 setup_logging("clitar", DEBUG_STDERR);
1830 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1833 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1838 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1839 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1841 DEBUG(0,("Error opening local file %s - %s\n",
1842 argv[Optind], strerror(errno)));