attr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:24k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * attr.c
  3.  *
  4.  * Copyright (C) 1996-1999 Martin von L鰓is
  5.  * Copyright (C) 1996-1997 R間is Duchesne
  6.  * Copyright (C) 1998 Joseph Malicki
  7.  * Copyright (C) 1999 Steve Dodd
  8.  * Copyright (C) 2001 Anton Altaparmakov (AIA)
  9.  */
  10. #include "ntfstypes.h"
  11. #include "struct.h"
  12. #include "attr.h"
  13. #include <linux/errno.h>
  14. #include <linux/ntfs_fs.h>
  15. #include "macros.h"
  16. #include "support.h"
  17. #include "util.h"
  18. #include "super.h"
  19. #include "inode.h"
  20. #include "unistr.h"
  21. /**
  22.  * ntfs_find_attr_in_mft_rec - find attribute in mft record
  23.  * @vol: volume on which attr resides
  24.  * @m: mft record to search
  25.  * @type: attribute type to find
  26.  * @name: attribute name to find (optional, i.e. NULL means don't care)
  27.  * @name_len: attribute name length (only needed if @name present)
  28.  * @ic: ignore case if 1 or case sensitive if 0 (ignored if @name NULL)
  29.  * @instance: instance number to find
  30.  *
  31.  * Only search the specified mft record and it ignores the presence of an
  32.  * attribute list attribute (unless it is the one being searched for,
  33.  * obviously, in which case it is returned).
  34.  */
  35. ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type,
  36. wchar_t *name, __u32 name_len, int ic, __u16 instance)
  37. {
  38. ntfs_u8 *a;
  39. /* Iterate over attributes in mft record @m. */
  40. a = m + NTFS_GETU16(m + 20); /* attrs_offset */
  41. for (; a >= m && a <= m + vol->mft_record_size;
  42. a += NTFS_GETU32(a + 4 /* length */)) {
  43. /* We catch $END with this more general check, too... */
  44. if (NTFS_GETU32(a + 0 /* type */) > type)
  45. return NULL;
  46. if (!NTFS_GETU32(a + 4 /* length */))
  47. break;
  48. if (NTFS_GETU32(a + 0 /* type */) != type)
  49. continue;
  50. /* If @name is present, compare the two names. */
  51. if (name && !ntfs_are_names_equal(name, name_len, (wchar_t*)
  52. (a + NTFS_GETU16(a + 10 /* name_offset */)),
  53. a[9] /* name_length */, ic, vol->upcase,
  54. vol->upcase_length)) {
  55. register int rc;
  56. rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
  57. name, name_len, (wchar_t*)(a +
  58. NTFS_GETU16(a + 10 /* name_offset */)),
  59. a[9] /* name_length */, 1, 1);
  60. /*
  61.  * If @name collates before a->name, there is no
  62.  * matching attribute.
  63.  */
  64. if (rc == -1)
  65. return NULL;
  66. /* If the strings are not equal, continue search. */
  67. if (rc)
  68.   continue;
  69. rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
  70. name, name_len, (wchar_t*)(a +
  71. NTFS_GETU16(a + 10 /* name_offset */)),
  72. a[9] /* name_length */, 0, 1);
  73. if (rc == -1)
  74. return NULL;
  75. if (rc)
  76. continue;
  77. }
  78. /*
  79.  * The names match or @name not present. Check instance number.
  80.  * and if it matches we have found the attribute and are done.
  81.  */
  82. if (instance != NTFS_GETU16(a + 14 /* instance */))
  83. continue;
  84. ntfs_debug(DEBUG_FILE3, "ntfs_find_attr_in_mft_record: found: "
  85. "attr type 0x%x, instance number = 0x%x.n",
  86. NTFS_GETU32(a + 0), instance);
  87. return a;
  88. }
  89. ntfs_error("ntfs_find_attr_in_mft_record: mft record 0x%x is corrupt"
  90. ". Run chkdsk.n", m);
  91. return NULL;
  92. }
  93. /* Look if an attribute already exists in the inode, and if not, create it. */
  94. int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
  95.   void *value, int value_len, int *pos, int *found)
  96. {
  97. int do_insert = 0;
  98. int i, m;
  99. ntfs_attribute *a;
  100. for (i = 0; i < ino->attr_count; i++)
  101. {
  102. a = ino->attrs + i;
  103. if (a->type < type)
  104. continue;
  105. if (a->type > type) {
  106. do_insert = 1;
  107. break;
  108. }
  109. /* If @name is present, compare the two names. */
  110. if (namelen && !ntfs_are_names_equal((wchar_t*)name, namelen,
  111. a->name, a->namelen /* name_length */,
  112. 1 /* ignore case*/, ino->vol->upcase,
  113. ino->vol->upcase_length)) {
  114. register int rc;
  115. rc = ntfs_collate_names(ino->vol->upcase,
  116. ino->vol->upcase_length, a->name,
  117. a->namelen, (wchar_t*)name, namelen,
  118. 1 /* ignore case */, 1);
  119. if (rc == -1)
  120. continue;
  121. if (rc == 1) {
  122.   do_insert = 1;
  123. break;
  124. }
  125. rc = ntfs_collate_names(ino->vol->upcase,
  126. ino->vol->upcase_length, a->name,
  127. a->namelen, (wchar_t*)name, namelen,
  128. 0 /* case sensitive */, 1);
  129. if (rc == -1)
  130. continue;
  131. if (rc == 1) {
  132. do_insert = 1;
  133. break;
  134. }
  135. }
  136. /* Names are equal or no name was asked for. */
  137. /* If a value was specified compare the values. */
  138. if (value_len && a->resident) {
  139. if (!a->resident) {
  140. ntfs_error("ntfs_new_attr: Value specified but "
  141. "attribute non-resident. Bug!n");
  142. return -EINVAL;
  143. }
  144. m = value_len;
  145. if (m > a->size)
  146. m = a->size;
  147. m = memcmp(value, a->d.data, m);
  148. if (m > 0)
  149. continue;
  150. if (m < 0) {
  151. do_insert = 1;
  152. break;
  153. }
  154. /* Values match until min of value lengths. */
  155. if (value_len > a->size)
  156. continue;
  157. if (value_len < a->size) {
  158. do_insert = 1;
  159. break;
  160. }
  161. }
  162. /* Full match! */
  163. *found = 1;
  164. *pos = i;
  165. return 0;
  166. }
  167. /* Re-allocate space. */
  168. if (ino->attr_count % 8 == 0)
  169. {
  170. ntfs_attribute* new;
  171. new = (ntfs_attribute*)ntfs_malloc((ino->attr_count + 8) *
  172. sizeof(ntfs_attribute));
  173. if (!new)
  174. return -ENOMEM;
  175. if (ino->attrs) {
  176. ntfs_memcpy(new, ino->attrs, ino->attr_count *
  177. sizeof(ntfs_attribute));
  178. ntfs_free(ino->attrs);
  179. }
  180. ino->attrs = new;
  181. }
  182. if (do_insert)
  183. ntfs_memmove(ino->attrs + i + 1, ino->attrs + i,
  184.      (ino->attr_count - i) * sizeof(ntfs_attribute));
  185. ino->attr_count++;
  186. ino->attrs[i].type = type;
  187. ino->attrs[i].namelen = namelen;
  188. ino->attrs[i].name = name;
  189. *pos = i;
  190. *found = 0;
  191. return 0;
  192. }
  193. int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr)
  194. {
  195. __s64 size = attr->size;
  196. if (size > 0) {
  197. /* FIXME: read data, free clusters */
  198. return -EOPNOTSUPP;
  199. }
  200. attr->resident = 1;
  201. return 0;
  202. }
  203. /* Store in the inode readable information about a run. */
  204. int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
  205.      int len)
  206. {
  207. /* (re-)allocate space if necessary. */
  208. if ((attr->d.r.len * sizeof(ntfs_runlist)) % PAGE_SIZE == 0) {
  209. ntfs_runlist* new;
  210. unsigned long new_size;
  211. ntfs_debug(DEBUG_MALLOC, "ntfs_insert_run: re-allocating "
  212. "space: old attr->d.r.len = 0x%xn",
  213. attr->d.r.len);
  214. new_size = attr->d.r.len * sizeof(ntfs_runlist) + PAGE_SIZE;
  215. if ((new_size >> PAGE_SHIFT) > num_physpages) {
  216. ntfs_error("ntfs_insert_run: attempted to allocate "
  217. "more pages than num_physpages."
  218. "This might be a bug or a corrupt"
  219. "file system.n");
  220. return -1;
  221. }
  222. new = ntfs_vmalloc(new_size);
  223. if (!new) {
  224. ntfs_error("ntfs_insert_run: ntfs_vmalloc(new_size = "
  225. "0x%x) failedn", new_size);
  226. return -1;
  227. }
  228. if (attr->d.r.runlist) {
  229. ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
  230. * sizeof(ntfs_runlist));
  231. ntfs_vfree(attr->d.r.runlist);
  232. }
  233. attr->d.r.runlist = new;
  234. }
  235. if (attr->d.r.len > cnum)
  236. ntfs_memmove(attr->d.r.runlist + cnum + 1,
  237.      attr->d.r.runlist + cnum,
  238.      (attr->d.r.len - cnum) * sizeof(ntfs_runlist));
  239. attr->d.r.runlist[cnum].lcn = cluster;
  240. attr->d.r.runlist[cnum].len = len;
  241. attr->d.r.len++;
  242. return 0;
  243. }
  244. /**
  245.  * ntfs_extend_attr - extend allocated size of an attribute
  246.  * @ino: ntfs inode containing the attribute to extend
  247.  * @attr: attribute which to extend
  248.  * @len: desired new length for @attr (_not_ the amount to extend by)
  249.  *
  250.  * Extends an attribute. Allocate clusters on the volume which @ino belongs to.
  251.  * Extends the run list accordingly, preferably by extending the last run of
  252.  * the existing run list, first.
  253.  *
  254.  * Only modifies attr->allocated, i.e. doesn't touch attr->size, nor
  255.  * attr->initialized.
  256.  */
  257. int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len)
  258. {
  259. int rlen, rl2_len, err = 0;
  260. ntfs_cluster_t cluster, clen;
  261. ntfs_runlist *rl, *rl2;
  262. if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
  263. ino->record_count > 1)
  264. return -EOPNOTSUPP;
  265. /*
  266.  * FIXME: Don't make non-resident if the attribute type is not right.
  267.  * For example cannot make index attribute non-resident! (AIA)
  268.  */
  269. if (attr->resident) {
  270. err = ntfs_make_attr_nonresident(ino, attr);
  271. if (err)
  272. return err;
  273. }
  274. if (len <= attr->allocated)
  275. return 0; /* Truly stupid things do sometimes happen. */
  276. rl = attr->d.r.runlist;
  277. rlen = attr->d.r.len;
  278. if (rlen > 0)
  279. cluster = rl[rlen - 1].lcn + rl[rlen - 1].len;
  280. else
  281. /* No preference for allocation space. */
  282. cluster = (ntfs_cluster_t)-1;
  283. /*
  284.  * Calculate the extra space we need, and round up to multiple of
  285.  * cluster size to get number of new clusters needed.
  286.  */
  287. clen = (len - attr->allocated + ino->vol->cluster_size - 1) >>
  288. ino->vol->cluster_size_bits;
  289. if (!clen)
  290. return 0;
  291. err = ntfs_allocate_clusters(ino->vol, &cluster, &clen, &rl2,
  292. &rl2_len, DATA_ZONE);
  293. if (err)
  294. return err;
  295. attr->allocated += (__s64)clen << ino->vol->cluster_size_bits;
  296. if (rlen > 0) {
  297. err = splice_runlists(&rl, &rlen, rl2, rl2_len);
  298. ntfs_vfree(rl2);
  299. if (err)
  300. return err;
  301. } else {
  302. if (rl)
  303. ntfs_vfree(rl);
  304. rl = rl2;
  305. rlen = rl2_len;
  306. }
  307. attr->d.r.runlist = rl;
  308. attr->d.r.len = rlen;
  309. return 0;
  310. }
  311. int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
  312. {
  313. int error;
  314. ntfs_io io;
  315. void *data = attr->d.data;
  316. __s64 len = attr->size;
  317. attr->d.r.len = 0;
  318. attr->d.r.runlist = NULL;
  319. attr->resident = 0;
  320. /*
  321.  * ->allocated is updated by ntfs_extend_attr(), while ->initialized
  322.  * and ->size are updated by ntfs_readwrite_attr(). (AIA)
  323.  */
  324. attr->allocated = attr->initialized = 0;
  325. error = ntfs_extend_attr(ino, attr, len);
  326. if (error)
  327. return error; /* FIXME: On error, restore old values. */
  328. io.fn_put = ntfs_put;
  329. io.fn_get = ntfs_get;
  330. io.param = data;
  331. io.size = len;
  332. io.do_read = 0;
  333. return ntfs_readwrite_attr(ino, attr, 0, &io);
  334. }
  335. int ntfs_attr_allnonresident(ntfs_inode *ino)
  336. {
  337. int i, error = 0;
  338.         ntfs_volume *vol = ino->vol;
  339. for (i = 0; !error && i < ino->attr_count; i++)
  340. {
  341. if (ino->attrs[i].type != vol->at_security_descriptor &&
  342.     ino->attrs[i].type != vol->at_data)
  343. continue;
  344. error = ntfs_make_attr_nonresident(ino, ino->attrs + i);
  345. }
  346. return error;
  347. }
  348. /*
  349.  * Resize the attribute to a newsize. attr->allocated and attr->size are
  350.  * updated, but attr->initialized is not changed unless it becomes bigger than
  351.  * attr->size, in which case it is set to attr->size.
  352.  */
  353. int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
  354. {
  355. int error = 0;
  356. __s64 oldsize = attr->size;
  357. int clustersizebits = ino->vol->cluster_size_bits;
  358. int i, count, newcount;
  359. ntfs_runlist *rl, *rlt;
  360. if (newsize == oldsize)
  361. return 0;
  362. if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
  363. return -EOPNOTSUPP;
  364. if (attr->resident) {
  365. void *v;
  366. if (newsize > ino->vol->mft_record_size) {
  367. error = ntfs_make_attr_nonresident(ino, attr);
  368. if (error)
  369. return error;
  370. return ntfs_resize_attr(ino, attr, newsize);
  371. }
  372. v = attr->d.data;
  373. if (newsize) {
  374. __s64 minsize = newsize;
  375. attr->d.data = ntfs_malloc(newsize);
  376. if (!attr->d.data) {
  377. ntfs_free(v);
  378. return -ENOMEM;
  379. }
  380. if (newsize > oldsize) {
  381. minsize = oldsize;
  382. ntfs_bzero((char*)attr->d.data + oldsize,
  383.    newsize - oldsize);
  384. }
  385. ntfs_memcpy((char*)attr->d.data, v, minsize);
  386. } else
  387. attr->d.data = 0;
  388. ntfs_free(v);
  389. attr->size = newsize;
  390. return 0;
  391. }
  392. /* Non-resident attribute. */
  393. rl = attr->d.r.runlist;
  394. if (newsize < oldsize) {
  395. int rl_size;
  396. /*
  397.  * FIXME: We might be going awfully wrong for newsize = 0,
  398.  * possibly even leaking memory really badly. But considering
  399.  * in that case there is more breakage due to -EOPNOTSUPP stuff
  400.  * further down the code path, who cares for the moment... (AIA)
  401.  */
  402. for (i = 0, count = 0; i < attr->d.r.len; i++) {
  403. if ((__s64)(count + rl[i].len) << clustersizebits >
  404. newsize) {
  405. i++;
  406. break;
  407. }
  408. count += (int)rl[i].len;
  409. }
  410. newcount = count;
  411. /* Free unused clusters in current run, unless sparse. */
  412. if (rl[--i].lcn != (ntfs_cluster_t)-1) {
  413. ntfs_cluster_t rounded = newsize - ((__s64)count <<
  414. clustersizebits);
  415. rounded = (rounded + ino->vol->cluster_size - 1) >>
  416. clustersizebits;
  417. error = ntfs_deallocate_cluster_run(ino->vol, 
  418. rl[i].lcn + rounded,
  419. rl[i].len - rounded);
  420. if (error)
  421. return error; /* FIXME: Incomplete operation. */
  422. rl[i].len = rounded;
  423. newcount = count + rounded;
  424. }
  425. /* Free all other runs. */
  426. i++;
  427. error = ntfs_deallocate_clusters(ino->vol, rl + i,
  428. attr->d.r.len - i);
  429. if (error)
  430. return error; /* FIXME: Incomplete operation. */
  431. /*
  432.  * Free space for extra runs in memory if enough memory left
  433.  * to do so. FIXME: Only do it if it would free memory. (AIA)
  434.  */
  435. rl_size = ((i + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
  436. PAGE_MASK;
  437. if (rl_size < ((attr->d.r.len * sizeof(ntfs_runlist) +
  438. PAGE_SIZE - 1) & PAGE_MASK)) {
  439. rlt = ntfs_vmalloc(rl_size);
  440. if (rlt) {
  441. ntfs_memcpy(rlt, rl, i * sizeof(ntfs_runlist));
  442. ntfs_vfree(rl);
  443. attr->d.r.runlist = rl = rlt;
  444. }
  445. }
  446. rl[i].lcn = (ntfs_cluster_t)-1;
  447. rl[i].len = (ntfs_cluster_t)0;
  448. attr->d.r.len = i;
  449. } else {
  450. error = ntfs_extend_attr(ino, attr, newsize);
  451. if (error)
  452. return error; /* FIXME: Incomplete operation. */
  453. newcount = (newsize + ino->vol->cluster_size - 1) >>
  454. clustersizebits;
  455. }
  456. /* Fill in new sizes. */
  457. attr->allocated = (__s64)newcount << clustersizebits;
  458. attr->size = newsize;
  459. if (attr->initialized > newsize)
  460. attr->initialized = newsize;
  461. if (!newsize)
  462. error = ntfs_make_attr_resident(ino, attr);
  463. return error;
  464. }
  465. int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
  466. int dsize, ntfs_attribute **rattr)
  467. {
  468. void *name;
  469. int namelen;
  470. int found, i;
  471. int error;
  472. ntfs_attribute *attr;
  473. if (dsize > ino->vol->mft_record_size)
  474. /* FIXME: Non-resident attributes. */
  475. return -EOPNOTSUPP;
  476. if (aname) {
  477. namelen = strlen(aname);
  478. name = ntfs_malloc(2 * namelen);
  479. if (!name)
  480. return -ENOMEM;
  481. ntfs_ascii2uni(name, aname, namelen);
  482. } else {
  483. name = 0;
  484. namelen = 0;
  485. }
  486. error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
  487. &found);
  488. if (error || found) {
  489. ntfs_free(name);
  490. return error ? error : -EEXIST;
  491. }
  492. *rattr = attr = ino->attrs + i;
  493. /* Allocate a new number.
  494.  * FIXME: Should this happen on inode writeback?
  495.  * FIXME: Extension records not supported. */
  496. error = ntfs_allocate_attr_number(ino, &i);
  497. if (error)
  498. return error;
  499. attr->attrno = i;
  500. if (attr->attrno + 1 != NTFS_GETU16(ino->attr + 0x28))
  501. ntfs_error("UH OH! attr->attrno (%i) != NTFS_GETU16(ino->attr "
  502. "+ 0x28) (%i)n", attr->attrno,
  503. NTFS_GETU16(ino->attr + 0x28));
  504. attr->resident = 1;
  505. attr->flags = 0;
  506. attr->cengine = 0;
  507. attr->size = attr->allocated = attr->initialized = dsize;
  508. /* FIXME: INDEXED information should come from $AttrDef
  509.  * Currently, only file names are indexed. As of NTFS v3.0 (Win2k),
  510.  * this is no longer true. Different attributes can be indexed now. */
  511. if (anum == ino->vol->at_file_name)
  512. attr->indexed = 1;
  513. else
  514. attr->indexed = 0;
  515. attr->d.data = ntfs_malloc(dsize);
  516. if (!attr->d.data)
  517. return -ENOMEM;
  518. ntfs_memcpy(attr->d.data, data, dsize);
  519. return 0;
  520. }
  521. /*
  522.  * Non-resident attributes are stored in runs (intervals of clusters).
  523.  *
  524.  * This function stores in the inode readable information about a non-resident
  525.  * attribute.
  526.  */
  527. static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr,
  528. unsigned char *data)
  529. {
  530. int startvcn, endvcn;
  531. int vcn, cnum;
  532. ntfs_cluster_t cluster;
  533. int len, ctype;
  534. int er = 0;
  535. startvcn = NTFS_GETS64(data + 0x10);
  536. endvcn = NTFS_GETS64(data + 0x18);
  537. /* Check whether this chunk really belongs to the end. Problem with
  538.  * this: this functions can get called on the last extent first, before
  539.  * it is called on the other extents in sequence. This happens when the
  540.  * base mft record contains the last extent instead of the first one
  541.  * and the first extent is stored, like any intermediate extents in
  542.  * extension mft records. This would be difficult to allow the way the
  543.  * runlist is stored in memory. Thus we fix elsewhere by causing the
  544.  * attribute list attribute to be processed immediately when found. The
  545.  * extents will then be processed starting with the first one. */
  546. for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
  547. vcn += attr->d.r.runlist[cnum].len;
  548. if (vcn != startvcn) {
  549. ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: ino = 0x%x, "
  550. "attr->type = 0x%x, startvcn = 0x%x, endvcn = 0x%x, "
  551. "vcn = 0x%x, cnum = 0x%xn", ino->i_number, attr->type,
  552. startvcn, endvcn, vcn, cnum);
  553. if (vcn < startvcn) {
  554. ntfs_error("Problem with runlist in extended recordn");
  555. return -1;
  556. }
  557. /* Tried to insert an already inserted runlist. */
  558. return 0;
  559. }
  560. if (!endvcn) {
  561. if (!startvcn) {
  562. /* Allocated length. */
  563. endvcn = NTFS_GETS64(data + 0x28) - 1;
  564. endvcn >>= ino->vol->cluster_size_bits;
  565. } else {
  566. /* This is an extent. Allocated length is not defined!
  567.  * Extents must have an endvcn though so this is an
  568.  * error. */
  569. ntfs_error("Corrupt attribute extent. (endvcn is "
  570. "missing)n");
  571. return -1;
  572. }
  573. }
  574. data = data + NTFS_GETU16(data + 0x20);
  575. cnum = attr->d.r.len;
  576. cluster = 0;
  577. for (vcn = startvcn; vcn <= endvcn; vcn += len) {
  578. if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) {
  579. ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: "
  580. "ntfs_decompress_run failed. i_number = 0x%xn",
  581. ino->i_number);
  582. return -1;
  583. }
  584. if (ctype)
  585. er = ntfs_insert_run(attr, cnum, -1, len);
  586. else
  587. er = ntfs_insert_run(attr, cnum, cluster, len);
  588. if (er)
  589. break;
  590. cnum++;
  591. }
  592. if (er)
  593. ntfs_error("ntfs_process_runs: ntfs_insert_run failedn");
  594. ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: startvcn = 0x%x, vcn = 0x%x"
  595. ", endvcn = 0x%x, cnum = %in", startvcn, vcn,
  596. endvcn, cnum);
  597. return er;
  598. }
  599.   
  600. /* Insert the attribute starting at attr in the inode ino. */
  601. int ntfs_insert_attribute(ntfs_inode *ino, unsigned char *attrdata)
  602. {
  603. int i, found;
  604. int type;
  605. short int *name;
  606. int namelen;
  607. void *data;
  608. ntfs_attribute *attr;
  609. int error;
  610. type = NTFS_GETU32(attrdata);
  611. namelen = NTFS_GETU8(attrdata + 9);
  612. ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ino->i_number 0x%x, "
  613. "attr type 0x%xn", ino->i_number, type);
  614. /* Read the attribute's name if it has one. */
  615. if (!namelen)
  616. name = 0;
  617. else {
  618. /* 1 Unicode character fits in 2 bytes. */
  619. name = ntfs_malloc(2 * namelen);
  620. if (!name)
  621. return -ENOMEM;
  622. ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10),
  623.     2 * namelen);
  624. }
  625. /* If resident look for value, too. */
  626. if (NTFS_GETU8(attrdata + 8) == 0)
  627. error = ntfs_new_attr(ino, type, name, namelen,
  628. attrdata + NTFS_GETU16(attrdata + 0x14),
  629. NTFS_GETU16(attrdata + 0x10), &i, &found);
  630. else
  631. error = ntfs_new_attr(ino, type, name, namelen, NULL, 0, &i,
  632. &found);
  633. if (error) {
  634. ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ntfs_new_attr "
  635. "failed.n");
  636. if (name)
  637. ntfs_free(name);
  638. return error;
  639. }
  640. if (found) {
  641. /* It's already there, if not resident just process the runs. */
  642. if (!ino->attrs[i].resident) {
  643. ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute:"
  644. " processing runs 1.n");
  645. /* FIXME: Check error code! (AIA) */
  646. ntfs_process_runs(ino, ino->attrs + i, attrdata);
  647. }
  648. return 0;
  649. }
  650. attr = ino->attrs + i;
  651. attr->resident = NTFS_GETU8(attrdata + 8) == 0;
  652. attr->flags = *(__u16*)(attrdata + 0xC);
  653. attr->attrno = NTFS_GETU16(attrdata + 0xE);
  654.   
  655. if (attr->resident) {
  656. attr->size = NTFS_GETU16(attrdata + 0x10);
  657. data = attrdata + NTFS_GETU16(attrdata + 0x14);
  658. attr->d.data = (void*)ntfs_malloc(attr->size);
  659. if (!attr->d.data)
  660. return -ENOMEM;
  661. ntfs_memcpy(attr->d.data, data, attr->size);
  662. attr->indexed = NTFS_GETU8(attrdata + 0x16);
  663. } else {
  664. attr->allocated = NTFS_GETS64(attrdata + 0x28);
  665. attr->size = NTFS_GETS64(attrdata + 0x30);
  666. attr->initialized = NTFS_GETS64(attrdata + 0x38);
  667. attr->cengine = NTFS_GETU16(attrdata + 0x22);
  668. if (attr->flags & ATTR_IS_COMPRESSED)
  669. attr->compsize = NTFS_GETS64(attrdata + 0x40);
  670. ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
  671. "attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
  672. "attr->initialized = 0x%Lxn", attr->allocated,
  673. attr->size, attr->initialized);
  674. ino->attrs[i].d.r.runlist = 0;
  675. ino->attrs[i].d.r.len = 0;
  676. ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: processing "
  677. "runs 2.n");
  678. /* FIXME: Check error code! (AIA) */
  679. ntfs_process_runs(ino, attr, attrdata);
  680. }
  681. return 0;
  682. }
  683. int ntfs_read_zero(ntfs_io *dest, int size)
  684. {
  685. int i;
  686. char *sparse = ntfs_calloc(512);
  687. if (!sparse)
  688. return -ENOMEM;
  689. i = 512;
  690. while (size) {
  691. if (i > size)
  692. i = size;
  693. dest->fn_put(dest, sparse, i);
  694. size -= i;
  695. }
  696. ntfs_free(sparse);
  697. return 0;
  698. }
  699. /* Process compressed attributes. */
  700. int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
  701.  ntfs_io *dest)
  702. {
  703. int error = 0;
  704. int clustersizebits;
  705. int s_vcn, rnum, vcn, got, l1;
  706. __s64 copied, len, chunk, offs1, l, chunk2;
  707. ntfs_cluster_t cluster, cl1;
  708. char *comp = 0, *comp1;
  709. char *decomp = 0;
  710. ntfs_io io;
  711. ntfs_runlist *rl;
  712. l = dest->size;
  713. clustersizebits = ino->vol->cluster_size_bits;
  714. /* Starting cluster of potential chunk. There are three situations:
  715.    a) In a large uncompressible or sparse chunk, s_vcn is in the middle
  716.       of a run.
  717.    b) s_vcn is right on a run border.
  718.    c) When several runs make a chunk, s_vcn is before the chunks. */
  719. s_vcn = offset >> clustersizebits;
  720. /* Round down to multiple of 16. */
  721. s_vcn &= ~15;
  722. rl = attr->d.r.runlist;
  723. for (rnum = vcn = 0; rnum < attr->d.r.len && vcn + rl->len <= s_vcn;
  724. rnum++, rl++)
  725. vcn += rl->len;
  726. if (rnum == attr->d.r.len) {
  727. /* Beyond end of file. */
  728. /* FIXME: Check allocated / initialized. */
  729. dest->size = 0;
  730. return 0;
  731. }
  732. io.do_read = 1;
  733. io.fn_put = ntfs_put;
  734. io.fn_get = 0;
  735. cluster = rl->lcn;
  736. len = rl->len;
  737. copied = 0;
  738. while (l) {
  739. chunk = 0;
  740. if (cluster == (ntfs_cluster_t)-1) {
  741. /* Sparse cluster. */
  742. __s64 ll;
  743. if ((len - (s_vcn - vcn)) & 15)
  744. ntfs_error("Unexpected sparse chunk size.");
  745. ll = ((__s64)(vcn + len) << clustersizebits) - offset;
  746. if (ll > l)
  747. ll = l;
  748. chunk = ll;
  749. error = ntfs_read_zero(dest, ll);
  750. if (error)
  751. goto out;
  752. } else if (dest->do_read) {
  753. if (!comp) {
  754. comp = ntfs_malloc(16 << clustersizebits);
  755. if (!comp) {
  756. error = -ENOMEM;
  757. goto out;
  758. }
  759. }
  760. got = 0;
  761. /* We might need to start in the middle of a run. */
  762. cl1 = cluster + s_vcn - vcn;
  763. comp1 = comp;
  764. do {
  765. int delta;
  766. io.param = comp1;
  767. delta = s_vcn - vcn;
  768. if (delta < 0)
  769. delta = 0;
  770. l1 = len - delta;
  771. if (l1 > 16 - got)
  772. l1 = 16 - got;
  773. io.size = (__s64)l1 << clustersizebits;
  774. error = ntfs_getput_clusters(ino->vol, cl1, 0,
  775.              &io);
  776. if (error)
  777. goto out;
  778. if (l1 + delta == len) {
  779. rnum++;
  780. rl++;
  781. vcn += len;
  782. cluster = cl1 = rl->lcn;
  783. len = rl->len;
  784. }
  785. got += l1;
  786. comp1 += (__s64)l1 << clustersizebits;
  787. } while (cluster != (ntfs_cluster_t)-1 && got < 16);
  788. /* Until empty run. */
  789. chunk = 16 << clustersizebits;
  790. if (cluster != (ntfs_cluster_t)-1 || got == 16)
  791. /* Uncompressible */
  792. comp1 = comp;
  793. else {
  794. if (!decomp) {
  795. decomp = ntfs_malloc(16 << 
  796. clustersizebits);
  797. if (!decomp) {
  798. error = -ENOMEM;
  799. goto out;
  800. }
  801. }
  802. /* Make sure there are null bytes after the
  803.  * last block. */
  804. *(ntfs_u32*)comp1 = 0;
  805. ntfs_decompress(decomp, comp, chunk);
  806. comp1 = decomp;
  807. }
  808. offs1 = offset - ((__s64)s_vcn << clustersizebits);
  809. chunk2 = (16 << clustersizebits) - offs1;
  810. if (chunk2 > l)
  811. chunk2 = l;
  812. if (chunk > chunk2)
  813. chunk = chunk2;
  814. dest->fn_put(dest, comp1 + offs1, chunk);
  815. }
  816. l -= chunk;
  817. copied += chunk;
  818. offset += chunk;
  819. s_vcn = (offset >> clustersizebits) & ~15;
  820. if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
  821. rnum++;
  822. rl++;
  823. vcn += len;
  824. cluster = rl->lcn;
  825. len = rl->len;
  826. }
  827. }
  828. out:
  829. if (comp)
  830. ntfs_free(comp);
  831. if (decomp)
  832. ntfs_free(decomp);
  833. dest->size = copied;
  834. return error;
  835. }
  836. int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
  837. ntfs_io *dest)
  838. {
  839. return -EOPNOTSUPP;
  840. }