8 int mainstacksize = 128*1024;
10 typedef struct Sink Sink;
11 typedef struct MetaSink MetaSink;
12 typedef struct DirSink DirSink;
18 uchar *pbuf[VtPointerDepth+1];
26 uchar *p; /* current pointer */
27 uchar *ep; /* end pointer */
35 uchar *rp; /* start of current record */
36 uchar *p; /* current pointer */
37 uchar *ep; /* end pointer */
40 static void usage(void);
41 static int strpcmp(const void*, const void*);
42 static void warn(char *fmt, ...);
43 static void cleanup(void);
44 static u64int unittoull(char *s);
45 static void vac(VtConn *z, char *argv[]);
46 static void vacfile(DirSink *dsink, char *lname, char *sname, VacFile*);
47 static void vacstdin(DirSink *dsink, char *name, VacFile *vf);
48 static void vacdata(DirSink *dsink, int fd, char *lname, VacFile*, Dir*);
49 static void vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile*);
50 static int vacmerge(DirSink *dsink, char *lname, char *sname);
51 static int vacspecial(DirSink *dsink, Dir *dir, char *lname, char *sname, VacFile *vf);
52 Sink *sinkalloc(VtConn *z, int psize, int dsize);
53 void sinkwrite(Sink *k, uchar *data, int n);
54 void sinkwritescore(Sink *k, uchar *score, int n);
55 void sinkclose(Sink *k);
56 void sinkfree(Sink *k);
58 DirSink *dirsinkalloc(VtConn *z, int psize, int dsize);
59 void dirsinkwrite(DirSink *k, VtEntry*);
60 void dirsinkwritesink(DirSink *k, Sink*);
61 int dirsinkwritefile(DirSink *k, VacFile *vf);
62 void dirsinkclose(DirSink *k);
63 void dirsinkfree(DirSink *k);
65 MetaSink *metasinkalloc(VtConn *z, int psize, int dsize);
66 void metasinkputc(MetaSink *k, int c);
67 void metasinkputstring(MetaSink *k, char *s);
68 void metasinkputuint32(MetaSink *k, ulong x);
69 void metasinkputuint64(MetaSink *k, uvlong x);
70 void metasinkwrite(MetaSink *k, uchar *data, int n);
71 void metasinkwritedir(MetaSink *ms, VacDir *vd);
72 void metasinkeor(MetaSink *k);
73 void metasinkclose(MetaSink *k);
74 void metasinkfree(MetaSink *k);
75 void plan9tovacdir(VacDir*, Dir*, ulong entry, uvlong qid);
92 int bsize = BlockSize;
98 char *exclude[MaxExclude];
107 fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0);
108 threadexitsall("usage");
112 threadmain(int argc, char *argv[])
128 bsize = unittoull(p);
138 if(nexclude >= MaxExclude)
139 sysfatal("too many exclusions\n");
140 exclude[nexclude] = ARGF();
141 if(exclude[nexclude] == nil)
182 if(bsize > VtMaxLumpSize)
183 bsize = VtMaxLumpSize;
186 fmtinstall('V', vtscorefmt);
190 sysfatal("could not connect to server: %r");
193 sysfatal("vtconnect: %r");
195 qsort(exclude, nexclude, sizeof(char*), strpcmp);
200 fprint(2, "warning: could not ask server to flush pending writes: %r\n");
203 fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
204 stats.data, stats.skip, stats.sdata, stats.meta);
212 strpcmp(const void *p0, const void *p1)
214 return strcmp(*(char**)p0, *(char**)p1);
218 vacwrite(VtConn *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
222 sha1(buf, n, score, nil);
225 return vtwrite(z, score, type, buf, n);
229 lastelem(char *oname)
235 if((p = strrchr(oname, '/')) == nil)
241 vac(VtConn *z, char *argv[])
246 uchar score[VtScoreSize], buf[VtRootSize];
256 if(getwd(cwd, sizeof(cwd)) == 0)
257 sysfatal("can't find current directory: %r\n");
259 dsink = dirsinkalloc(z, bsize, bsize);
263 fs = vacfsopen(z, dfile, VtOREAD, 1000);
265 fprint(2, "could not open diff: %s: %r\n", dfile);
270 fd = create(oname, OWRITE, 0666);
272 sysfatal("could not create file: %s: %r", oname);
278 sysfatal("dirfstat failed: %r");
280 dir->name = lastelem(oname);
284 for(; *argv; argv++) {
287 for (cp = *argv; *cp; cp++)
299 vff = vacfileopen(fs, cp2);
300 vacfile(dsink, argv[0], cp2, vff);
303 if(cd && chdir(cwd) < 0)
304 sysfatal("can't cd back to %s: %r\n", cwd);
310 vff = vacfileopen(fs, isi);
311 vacstdin(dsink, isi, vff);
318 /* build meta information for the root */
319 ms = metasinkalloc(z, bsize, bsize);
320 /* fake into a directory */
321 dir->mode = DMDIR|0555;
322 dir->qid.type |= QTDIR;
323 plan9tovacdir(&vd, dir, 0, fileid++);
324 if(strcmp(vd.elem, "/") == 0){
326 vd.elem = vtstrdup("root");
328 metasinkwritedir(ms, &vd);
332 ds = dirsinkalloc(z, bsize, bsize);
333 dirsinkwritesink(ds, dsink->sink);
334 dirsinkwritesink(ds, dsink->msink->sink);
335 dirsinkwritesink(ds, ms->sink);
338 memset(&root, 0, sizeof(root));
339 strncpy(root.name, dir->name, sizeof(root.name));
340 root.name[sizeof(root.name)-1] = 0;
342 sprint(root.type, "vac");
343 memmove(root.score, ds->sink->dir.score, VtScoreSize);
344 root.blocksize = maxbsize;
346 vacfsgetscore(fs, root.prev);
354 vtrootpack(&root, buf);
355 if(vacwrite(z, score, VtRootType, buf, VtRootSize) < 0)
356 sysfatal("vacWrite failed: %r");
358 fprint(fd, "vac:%V\n", score);
360 /* avoid remove at cleanup */
365 isexcluded(char *name)
373 x = strcmp(exclude[i], name);
385 vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
392 if(isexcluded(lname)) {
393 warn("excluding: %s", lname);
397 if(merge && vacmerge(dsink, lname, sname) >= 0)
400 if((dir = dirstat(sname)) == nil){
401 warn("could not stat file %s: %r", lname);
404 if(dir->mode&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE)){
405 vacspecial(dsink, dir, lname, sname, vf);
408 }else if(dir->mode&DMSOCKET){
414 fd = open(sname, OREAD);
416 warn("could not open file: %s: %r", lname);
421 fprint(2, "%s\n", lname);
425 warn("can't stat %s: %r", lname);
429 dir->name = lastelem(sname);
431 entry = dsink->nentry;
433 if(dir->mode & DMDIR)
434 vacdir(dsink, fd, lname, sname, vf);
436 vacdata(dsink, fd, lname, vf, dir);
438 plan9tovacdir(&vd, dir, entry, fileid++);
439 metasinkwritedir(dsink->msink, &vd);
447 vacstdin(DirSink *dsink, char *name, VacFile *vf)
454 fprint(2, "%s\n", "<stdio>");
458 warn("can't stat <stdio>: %r");
463 entry = dsink->nentry;
465 vacdata(dsink, 0, "<stdin>", vf, dir);
467 plan9tovacdir(&vd, dir, entry, fileid++);
468 vd.elem = vtstrdup(name);
469 metasinkwritedir(dsink->msink, &vd);
476 sha1check(u8int *score, uchar *buf, int n)
478 uchar score2[VtScoreSize];
480 sha1(buf, n, score2, nil);
481 if(memcmp(score, score2, VtScoreSize) == 0)
487 vacdataskip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
491 uchar score[VtScoreSize];
493 /* skip blocks for append only files */
494 if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
495 warn("error seeking: %s", lname);
498 n = readn(fd, buf, bsize);
500 warn("error checking append only file: %s", lname);
503 if(vacfileblockscore(vf, blocks-1, score)<0 || sha1check(score, buf, n)<0) {
504 warn("last block of append file did not match: %s", lname);
508 for(i=0; i<blocks; i++) {
509 if(vacfileblockscore(vf, i, score) < 0) {
510 warn("could not get score: %s: %lud", lname, i);
511 seek(fd, i*bsize, 0);
515 sinkwritescore(sink, score, bsize);
525 vacdata(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
530 uchar score[VtScoreSize];
536 if(vf != nil && qdiff) {
537 vacfilegetdir(vf, &vd);
538 if(vd.mtime == dir->mtime)
539 if(vd.size == dir->length)
540 if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers)
541 if(dirsinkwritefile(dsink, vf)) {
547 /* look for an append only file */
548 if((dir->mode&DMAPPEND) != 0)
549 if(vd.size < dir->length)
551 if(vd.p9path == dir->qid.path)
552 vfblocks = vd.size/bsize;
558 buf = vtmalloc(bsize);
559 sink = sinkalloc(dsink->sink->z, bsize, bsize);
561 same = stats.sdata+stats.skip;
564 block += vacdataskip(sink, vf, fd, vfblocks, buf, lname);
566 if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
568 n = readn(fd, buf, bsize);
570 warn("file truncated due to read error: %s: %r", lname);
573 if(vf != nil && vacfileblockscore(vf, block, score)>=0 && sha1check(score, buf, n)>=0) {
575 sinkwritescore(sink, score, n);
577 sinkwrite(sink, buf, n);
580 same = stats.sdata+stats.skip - same;
582 if(same && (dir->mode&DMAPPEND) != 0)
583 if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n",
584 lname, block, same, vfblocks, block-same);
587 dirsinkwritesink(dsink, sink);
594 vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf)
603 ds = dirsinkalloc(dsink->sink->z, bsize, bsize);
604 while((nd = dirread(fd, &dirs)) > 0){
605 for(i = 0; i < nd; i++){
607 /* check for bad file names */
608 if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
610 ln = vtmalloc(strlen(lname) + strlen(name) + 2);
611 sn = vtmalloc(strlen(sname) + strlen(name) + 2);
612 sprint(ln, "%s/%s", lname, name);
613 sprint(sn, "%s/%s", sname, name);
615 vvf = vacfilewalk(vf, name);
618 vacfile(ds, ln, sn, vvf);
627 dirsinkwritesink(dsink, ds->sink);
628 dirsinkwritesink(dsink, ds->msink->sink);
633 vacmergefile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
635 uchar buf[VtEntrySize];
639 if(vacfileread(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
640 warn("could not read venti dir entry: %s\n", dir->elem);
643 vtentryunpack(&dd, buf, 0);
645 if(dir->mode & ModeDir) {
650 if(vacfileread(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) {
651 warn("could not read venti dir entry: %s\n", dir->elem);
654 vtentryunpack(&md, buf, 0);
657 /* max might incorrect in some old dumps */
658 if(dir->qid >= *max) {
659 warn("qid out of range: %s", dir->elem);
664 dir->entry = dsink->nentry;
667 dir->qidoffset += offset;
670 dir->qidoffset = offset;
674 dirsinkwrite(dsink, &dd);
675 if(dir->mode & ModeDir)
676 dirsinkwrite(dsink, &md);
677 metasinkwritedir(dsink->msink, dir);
683 vacmerge(DirSink *dsink, char *lname, char *sname)
692 if((p=strrchr(sname, '.')) == nil || strcmp(p, ".vac") != 0)
696 fs = vacfsopen(dsink->sink->z, sname, VtOREAD, 100);
700 vf = vacfileopen(fs, "/");
703 max = vacfilegetid(vf);
709 fprint(2, "merging: %s\n", lname);
711 if(maxbsize < fs->bsize)
712 maxbsize = fs->bsize;
715 if(vderead(d, &dir) < 1)
717 vacmergefile(dsink, vf, &dir, fileid, &max);
732 vacspecial(DirSink *dsink, Dir* dir, char *lname, char *sname, VacFile *vf)
735 int buflen, dtype, major, minor, n;
742 buf = malloc(buflen);
747 fprint(2, "%s\n", lname);
749 dir->name = lastelem(sname);
751 if(dir->mode & DMSYMLINK){
752 while((n = readlink(sname, buf, buflen)) == buflen){
754 btmp = vtrealloc(buf, buflen);
762 dir->mode |= DMSYMLINK;
763 }else if(dir->mode & DMDEVICE){
764 dtype = (dir->qid.path >> 16) & 0xFF;
765 minor = dir->qid.path & 0xff;
766 major = (dir->qid.path >> 8) & 0xFF;
767 n = snprint(buf, buflen, "%c %d %d", dtype, major, minor);
770 entry = dsink->nentry;
772 sink = sinkalloc(dsink->sink->z, bsize, bsize);
773 sinkwrite(sink, (uchar*)buf, n);
775 dirsinkwritesink(dsink, sink);
779 dir->name = lastelem(sname);
781 plan9tovacdir(&vd, dir, entry, fileid++);
782 metasinkwritedir(dsink->msink, &vd);
790 sinkalloc(VtConn *z, int psize, int dsize)
795 if(psize < 512 || psize > VtMaxLumpSize)
796 sysfatal("sinkalloc: bad psize");
797 if(dsize < 512 || dsize > VtMaxLumpSize)
798 sysfatal("sinkalloc: bad psize");
800 psize = VtScoreSize*(psize/VtScoreSize);
802 k = vtmallocz(sizeof(Sink));
804 k->dir.flags = VtEntryActive;
805 k->dir.psize = psize;
806 k->dir.dsize = dsize;
807 k->buf = vtmallocz(VtPointerDepth*k->dir.psize + VtScoreSize);
808 for(i=0; i<=VtPointerDepth; i++)
809 k->pbuf[i] = k->buf + i*k->dir.psize;
814 sinkwritescore(Sink *k, uchar score[VtScoreSize], int n)
820 memmove(k->pbuf[0], score, VtScoreSize);
824 for(i=0; i<VtPointerDepth; i++) {
825 k->pbuf[i] += VtScoreSize;
826 if(k->pbuf[i] < k->buf + d->psize*(i+1))
828 if(i == VtPointerDepth-1)
829 sysfatal("file too big");
830 p = k->buf+i*d->psize;
832 if(vacwrite(k->z, k->pbuf[i+1], VtDataType+1+i, p, d->psize) < 0)
833 sysfatal("vacwrite failed: %r");
837 /* round size up to multiple of dsize */
838 d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize);
844 sinkwrite(Sink *k, uchar *p, int n)
847 uchar score[VtScoreSize];
853 sysfatal("sinkWrite: size too big");
855 if((k->dir.type&~VtTypeDepthMask) == VtDirType){
862 if(vacwrite(k->z, score, type, p, n) < 0)
863 sysfatal("vacWrite failed: %r");
865 sinkwritescore(k, score, n);
869 sizetodepth(uvlong s, int psize, int dsize)
874 /* determine pointer depth */
875 np = psize/VtScoreSize;
876 s = (s + dsize - 1)/dsize;
877 for(d = 0; s > 1; d++)
893 memmove(kd->score, vtzeroscore, VtScoreSize);
897 for(n=VtPointerDepth-1; n>0; n--)
898 if(k->pbuf[n] > k->buf + kd->psize*n)
901 base = kd->type&~VtTypeDepthMask;
902 kd->type = base + sizetodepth(kd->size, kd->psize, kd->dsize);
904 /* skip full part of tree */
905 for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
908 /* is the tree completely full */
909 if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
910 memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
915 /* clean up the edge */
917 p = k->buf+i*kd->psize;
919 if(vacwrite(k->z, k->pbuf[i+1], base+1+i, p, k->pbuf[i]-p) < 0)
920 sysfatal("vacWrite failed: %r");
921 k->pbuf[i+1] += VtScoreSize;
923 memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
934 dirsinkalloc(VtConn *z, int psize, int dsize)
939 ds = VtEntrySize*(dsize/VtEntrySize);
941 k = vtmallocz(sizeof(DirSink));
942 k->sink = sinkalloc(z, psize, ds);
943 k->sink->dir.type = VtDirType;
944 k->msink = metasinkalloc(z, psize, dsize);
945 k->buf = vtmalloc(ds);
952 dirsinkwrite(DirSink *k, VtEntry *dir)
954 if(k->p + VtEntrySize > k->ep) {
955 sinkwrite(k->sink, k->buf, k->p - k->buf);
958 vtentrypack(dir, k->p, 0);
964 dirsinkwritesink(DirSink *k, Sink *sink)
966 dirsinkwrite(k, &sink->dir);
970 dirsinkwritefile(DirSink *k, VacFile *vf)
974 if(vacfilegetvtentry(vf, &dir) < 0)
976 dirsinkwrite(k, &dir);
981 dirsinkclose(DirSink *k)
983 metasinkclose(k->msink);
985 sinkwrite(k->sink, k->buf, k->p - k->buf);
990 dirsinkfree(DirSink *k)
993 metasinkfree(k->msink);
999 metasinkalloc(VtConn *z, int psize, int dsize)
1003 k = vtmallocz(sizeof(MetaSink));
1004 k->sink = sinkalloc(z, psize, dsize);
1005 k->buf = vtmalloc(dsize);
1006 k->maxindex = dsize/100; /* 100 byte entries seems reasonable */
1009 k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize;
1010 k->ep = k->buf + dsize;
1014 /* hack to get base to compare routine - not reentrant */
1018 dircmp(const void *p0, const void *p1)
1023 /* name is first element of entry */
1025 q0 = blockbase + (q0[0]<<8) + q0[1];
1026 n0 = (q0[6]<<8) + q0[7];
1030 q1 = blockbase + (q1[0]<<8) + q1[1];
1031 n1 = (q1[6]<<8) + q1[7];
1035 return memcmp(q0, q1, n0);
1037 r = memcmp(q0, q1, n0);
1040 r = memcmp(q0, q1, n1);
1046 metasinkflush(MetaSink *k)
1054 assert(k->nindex <= k->maxindex);
1061 mb.nindex = k->nindex;
1062 mb.maxindex = k->maxindex;
1066 p += MetaHeaderSize;
1068 /* XXX this is not reentrant! */
1070 qsort(p, k->nindex, MetaIndexSize, dircmp);
1071 p += k->nindex*MetaIndexSize;
1073 memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize);
1074 p += (k->maxindex-k->nindex)*MetaIndexSize;
1076 sinkwrite(k->sink, k->buf, n);
1078 /* move down partial entry */
1080 memmove(p, k->rp, n);
1087 metasinkputc(MetaSink *k, int c)
1092 sysfatal("directory entry too large");
1098 metasinkputstring(MetaSink *k, char *s)
1101 metasinkputc(k, n>>8);
1103 metasinkwrite(k, (uchar*)s, n);
1107 metasinkputuint32(MetaSink *k, ulong x)
1109 metasinkputc(k, x>>24);
1110 metasinkputc(k, x>>16);
1111 metasinkputc(k, x>>8);
1116 metasinkputuint64(MetaSink *k, uvlong x)
1118 metasinkputuint32(k, x>>32);
1119 metasinkputuint32(k, x);
1123 metasinkwrite(MetaSink *k, uchar *data, int n)
1125 if(k->p + n > k->ep)
1127 if(k->p + n > k->ep)
1128 sysfatal("directory entry too large");
1130 memmove(k->p, data, n);
1135 metasinkwritedir(MetaSink *ms, VacDir *dir)
1137 metasinkputuint32(ms, DirMagic);
1138 metasinkputc(ms, Version>>8);
1139 metasinkputc(ms, Version);
1140 metasinkputstring(ms, dir->elem);
1141 metasinkputuint32(ms, dir->entry);
1142 metasinkputuint64(ms, dir->qid);
1143 metasinkputstring(ms, dir->uid);
1144 metasinkputstring(ms, dir->gid);
1145 metasinkputstring(ms, dir->mid);
1146 metasinkputuint32(ms, dir->mtime);
1147 metasinkputuint32(ms, dir->mcount);
1148 metasinkputuint32(ms, dir->ctime);
1149 metasinkputuint32(ms, dir->atime);
1150 metasinkputuint32(ms, dir->mode);
1153 metasinkputc(ms, DirPlan9Entry); /* plan9 extra info */
1154 metasinkputc(ms, 0); /* plan9 extra size */
1155 metasinkputc(ms, 12); /* plan9 extra size */
1156 metasinkputuint64(ms, dir->p9path);
1157 metasinkputuint32(ms, dir->p9version);
1160 if(dir->qidspace != 0) {
1161 metasinkputc(ms, DirQidSpaceEntry);
1162 metasinkputc(ms, 0);
1163 metasinkputc(ms, 16);
1164 metasinkputuint64(ms, dir->qidoffset);
1165 metasinkputuint64(ms, dir->qidmax);
1169 metasinkputc(ms, DirGenEntry);
1170 metasinkputc(ms, 0);
1171 metasinkputc(ms, 4);
1172 metasinkputuint32(ms, dir->gen);
1180 plan9tovacdir(VacDir *vd, Dir *dir, ulong entry, uvlong qid)
1182 memset(vd, 0, sizeof(VacDir));
1184 vd->elem = vtstrdup(dir->name);
1187 vd->uid = vtstrdup(dir->uid);
1188 vd->gid = vtstrdup(dir->gid);
1189 vd->mid = vtstrdup(dir->muid);
1190 vd->mtime = dir->mtime;
1192 vd->ctime = dir->mtime; /* ctime: not available on plan 9 */
1193 vd->atime = dir->atime;
1195 vd->mode = dir->mode & 0777;
1196 if(dir->mode & DMDIR)
1197 vd->mode |= ModeDir;
1198 if(dir->mode & DMAPPEND)
1199 vd->mode |= ModeAppend;
1200 if(dir->mode & DMEXCL)
1201 vd->mode |= ModeExclusive;
1202 if(dir->mode & DMDEVICE)
1203 vd->mode |= ModeDevice;
1204 if(dir->mode & DMNAMEDPIPE)
1205 vd->mode |= ModeNamedPipe;
1206 if(dir->mode & DMSYMLINK)
1207 vd->mode |= ModeLink;
1210 vd->p9path = dir->qid.path;
1211 vd->p9version = dir->qid.vers;
1216 metasinkeor(MetaSink *k)
1221 p = k->buf + MetaHeaderSize;
1222 p += k->nindex * MetaIndexSize;
1223 o = k->rp-k->buf; /* offset from start of block */
1224 n = k->p-k->rp; /* size of entry */
1231 if(k->nindex == k->maxindex)
1236 metasinkclose(MetaSink *k)
1243 metasinkfree(MetaSink *k)
1251 warn(char *fmt, ...)
1256 fprint(2, "%s: ", argv0);
1257 vfprint(2, fmt, arg);
1269 #define TWID64 ((u64int)~(u64int)0)
1279 n = strtoul(s, &es, 0);
1280 if(*es == 'k' || *es == 'K'){
1283 }else if(*es == 'm' || *es == 'M'){
1286 }else if(*es == 'g' || *es == 'G'){
1287 n *= 1024*1024*1024;